c# - 对 List<String> 进行排序时出现意外行为

标签 c# list linq cultureinfo

如果我尝试按以下方式对字符串列表进行排序:

List<String> lstStrings = new List<string>();

String s1 = "KÜHLSCHRANK";
String s2 = "KUHLSCHRANK";
int i = s1.CompareTo(s2);   // returns 1
int j = s2.CompareTo(s1);   // return -1 

i = StringComparer.InvariantCulture.Compare(s1, s2); // returns 1
j = StringComparer.InvariantCulture.Compare(s2, s1); // returns -1

lstStrings.Add("KÜHLSCHRANK1");
lstStrings.Add("KUTTER");
lstStrings.Add("KUHLSCHRANK2");
lstStrings.Add("KÜHLSCHRANK3");

var lstStrings1 = lstStrings.OrderBy(y => y).ToList();
var lstStrings2 = lstStrings.OrderBy(y => y, StringComparer.InvariantCulture).ToList();
var lstStrings3 = lstStrings.OrderBy(y => y, StringComparer.CurrentCulture).ToList();
var lstStrings4 = lstStrings.OrderBy(y => y, StringComparer.Ordinal).ToList();

我在 lstStrings1lstStrings2lstStrings3 中得到以下结果:

    [0] "KÜHLSCHRANK1"
    [1] "KUHLSCHRANK2"
    [2] "KÜHLSCHRANK3"
    [3] "KUTTER"

只有我的lstStrings4显示了我预期的结果:

    [0] "KUHLSCHRANK2"  
    [1] "KUTTER"    
    [2] "KÜHLSCHRANK1"
    [3] "KÜHLSCHRANK3"

谁能解释一下为什么德语“Ü”默认与普通“U”一样有线程?

为什么使用 StringComparer.InvariantCulture 的 OrderBy 不关心 StringComparer.InvariantCulture.Compare(s1, s2) 的结果(这意味着列表的排序就像我之前的 lstStrings4 一样)样本)?

有什么办法可以改变这种“默认行为”吗?

添加: 如果我将数字附加到字符串,则比较方法的结果会更改:

        String s1 = "KÜHLSCHRANK1";
        String s2 = "KUHLSCHRANK2";
        int i = s1.CompareTo(s2);   // returns -1
        int j = s2.CompareTo(s1);   // return 1 

        i = StringComparer.InvariantCulture.Compare(s1, s2); // returns -1
        j = StringComparer.InvariantCulture.Compare(s2, s1); // returns 1

所以我什至不明白,为什么我的第一个没有数字的测试在每次比较时不返回零...

第二个添加: 在 SQL Server 上:

DECLARE @tableDE TABLE (strName NVARCHAR(MAX) COLLATE German_PhoneBook_CI_AI)

INSERT INTO @tableDE (strName)
SELECT e FROM (VALUES('KUHLSCHRANK1'), ('KÜHLSCHRANK2')) f(e)

SELECT * FROM @tableDE ORDER BY strName

给出结果:

KÜHLSCHRANK2
KUHLSCHRANK1

结果: 如果我在 LinqToSql 中执行 OrderBy 并将结果放入列表中, List 变量上的新 OrderBy,即使具有相同的参数,也会更改元素的顺序。

最佳答案

我可以告诉你为什么序数会给你“预期”的结果。根据StringComparer.Ordinal的文档

The StringComparer returned by the Ordinal property performs a simple byte comparison that is independent of language. This is most appropriate when comparing strings that are generated programmatically or when comparing case-sensitive resources such as passwords.

所以U0x55Ü0x220 。这样就可以对不同的 U 进行排序。但这有一个问题,假设您添加了单词 KËTTER (可能不是一个真正的德语单词,但它是出于演示目的)。您的列表将按如下方式组织:

[0] "KUHLSCHRANK2"
[1] "KUTTER"
[2] "KËTTER"
[3] "KÜHLSCHRANK1"
[4] "KÜHLSCHRANK3"

如您所见 Ë位于两个不同的 U 之间,那是因为 Ë unicode 为 0x203 ,和55<203<220意味着 U<Ë<Ü

因此,如果您的目标是对字母进行排序,然后根据字母的重音进行排序,我建议不要使用 Ordinal。

现在,我无法发表评论,但是您确定要按字母进行组织,然后根据字母的重音进行排序吗?我还没有看到字典对带重音的字母和正常对应的字母进行区分,这可能就是为什么文化相关的排序不能给出您需要的结果的原因。

补充: 我在您的测试中添加了更多案例,因此现在未排序的完整列表看起来有点像这样

[0] "KÜHLSCHRANK1"
[1] "KUHLSCHRANK1"
[2] "KUTTER"
[3] "KUHLSCHRANK2"
[4] "KÜHLSCHRANK2"
[5] "KÜHLSCHRANK3"
[6] "KËTTER"

invariantCulture 和 current Culture 产生相同的结果,即:

[0] "KËTTER"
[1] "KUHLSCHRANK1"
[2] "KÜHLSCHRANK1"
[3] "KUHLSCHRANK2"
[4] "KÜHLSCHRANK2"
[5] "KÜHLSCHRANK3"
[6] "KUTTER"

因此,这表明只有在完整匹配(忽略重音符号)时重音符号才会发挥作用。并且非重音优先。

第二次添加:

根据维基百科

Ü, or ü, is a character that typically represents a close front rounded vowel [y]. It is classified as a separate letter in several extended Latin alphabets (including Azeri, Estonian, Hungarian and Turkish), but as the letter U with an umlaut/diaeresis in others such as Catalan, French, Galician, German, Occitan and Spanish.

所以在德语中,元音变音不是一个单独的字母,而只是一个重音,如果您要使用土耳其文化,它将被视为一个单独的字母。 所以当文化是土耳其语时的结果是:

[0] "KËTTER"
[1] "KUHLSCHRANK1"
[2] "KUHLSCHRANK2"
[3] "KUTTER"
[4] "KÜHLSCHRANK1"
[5] "KÜHLSCHRANK2"
[6] "KÜHLSCHRANK3"

这产生了我相信你想要的结果。只是这对于你的话来说是错误的文化。

对评论的回复:

正如您所指出的,电话簿确实按照您想要的方式组织,经过一番挖掘,.net 对德语使用了两种排序算法。 Documentation 当使用电话簿排序算法时,它会产生结果:

[0] "KËTTER"
[1] "KÜHLSCHRANK1"
[2] "KÜHLSCHRANK2"
[3] "KÜHLSCHRANK3"
[4] "KUHLSCHRANK1"
[5] "KUHLSCHRANK2"
[6] "KUTTER"

为了使用电话簿排序算法,请使用以下命令:

var germanPhone=new CultureInfo(0x00010407);
StringComparer germanPhoneICComp = StringComparer.Create(germanPhone, true);\\set to false if caps are important to you
var lstStrings7 = lstStrings.OrderBy(y => y, germanPhoneICComp).ToList();

关于c# - 对 List<String> 进行排序时出现意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44453137/

相关文章:

Python LINQ 类方法

c# - 根据工作日安排 Azure Functions

c# - 如何在 Nokia Imaging SDK 的 Filter Explorer 示例项目中添加自定义滤镜

c# - 在标签名称中使用变量

list - 计算 Scheme 列表中的数字或字符

python - 更改 New_dictionary 中键的名称,其中 New_dictionary 作为 Main_dictionary 的值

c++ - 在 C++ 中使用 vector 与列表的图形表示

c# - 了解 LINQ 查询和 ViewModel

c# - HashSet 允许重复项插入 - C#

c# - 在动态 linq 查询中使用变量