排序List <string>时出现意外行为

时间:2017-06-09 08:39:18

标签: 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();

我在 lstStrings1 lstStrings2 lstStrings3 中获得以下结果:

    [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)的结果(这意味着List在上一个示例中像我的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, List变量上的新OrderBy,即使具有相同的参数,也会改变元素的顺序。

1 个答案:

答案 0 :(得分:3)

我可以回答为什么序数会给你“预期”的结果。根据{{​​1}}

的文档
  

Ordinal属性返回的StringComparer执行一个独立于语言的简单字节比较。在比较以编程方式生成的字符串或比较区分大小写的资源(如密码)时,这是最合适的。

因此StringComparer.OrdinalU0x55Ü。所以这会把你不同的U排除在外。但是这有一个问题,让我们说你添加单词0x220(可能不是一个真正的德语单词,但它是出于演示目的)。您的列表将按此组织:

KËTTER

正如您所看到的,[0] "KUHLSCHRANK2" [1] "KUTTER" [2] "KËTTER" [3] "KÜHLSCHRANK1" [4] "KÜHLSCHRANK3" 介于两个不同的U之间,这是因为Ë的unicode为Ë0x203表示55<203<220 }。

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

现在,我不能发表评论,但你确定要用字母组织,然后按字母的重音排序。我没有看到字典在重音字母和普通字母之间产生差异,这可能就是为什么依赖文化的种类不会给出你需要的结果。

加入:  我在测试中添加了几个案例,所以现在完整的未分类列表看起来有点像这样

U<Ë<Ü

invariantCulture和当前的文化会产生相同的结果,那就是:

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

所以这说明只有完全匹配(忽略重音)才会发挥重音。而且,不公平的优先权。

第二次添加:

根据维基百科

  

Ü,或ü,是一个通常代表近前圆形元音[y]的字符。它在几个扩展的拉丁字母(包括阿塞拜疆语,爱沙尼亚语,匈牙利语和土耳其语)中被分类为单独的字母,但在其他字母如加泰罗尼亚语,法语,加利西亚语,德语,奥克西唐语和西班牙语中的字母U和变音符号/分音符。< / p>

所以在德语中,变音符号不是一个单独的字母,而只是一个口音,如果你使用土耳其文化,它将被视为一个单独的字母。 因此,文化土耳其的结果是:

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

这就是我相信你想要的结果。这对你的言论来说就是错误的文化。

对评论的回应:

正如您所指出的,电话簿确实可以按照您的需要进行整理,经过一些挖掘后,.net为德语使用了两种排序算法。 Documentation 当使用电话簿排序algorthim时,它会产生结果:

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

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

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