首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >C#与F#中的默认排序

C#与F#中的默认排序
EN

Stack Overflow用户
提问于 2015-06-23 17:31:24
回答 4查看 774关注 0票数 18

考虑一下分别在C#F#中对字符串进行排序的两段代码:

C#:

代码语言:javascript
复制
var strings = new[] { "Tea and Coffee", "Telephone", "TV" };
var orderedStrings = strings.OrderBy(s => s).ToArray();

F#:

代码语言:javascript
复制
let strings = [| "Tea and Coffee"; "Telephone"; "TV" |]
let orderedStrings =
    strings
    |> Seq.sortBy (fun s -> s)
    |> Seq.toArray

这两段代码返回不同的结果:

  • C#:茶和咖啡,电话,TV
  • F#:电视,茶和咖啡,电话

在我的特定案例中,我需要将这两种语言之间的排序逻辑关联起来(一种是产品代码,另一种是测试断言的一部分)。这提出了几个问题:

  • 排序逻辑上的差异有没有潜在的原因?
  • 在my
  • 中克服这个“问题”的推荐方法是什么这一现象特定于字符串,或者它也适用于其他.NET类型?

编辑

为了回应几个试探性的评论,运行下面的片段揭示了更多关于这种排序差异的确切性质:

F#:

代码语言:javascript
复制
let strings = [| "UV"; "Uv"; "uV"; "uv"; "Tv"; "TV"; "tv"; "tV" |]
let orderedStrings =
    strings
    |> Seq.sortBy (fun s -> s)
    |> Seq.toArray

C#:

代码语言:javascript
复制
var strings = new[] { "UV", "Uv", "uv", "uV", "TV", "tV", "Tv", "tv" };
var orderedStrings = strings.OrderBy(s => s).ToArray();

提供:

  • C#:Tv,TV,tV,TV,uv,uV,Uv,UV
  • F#:Tv,tV,UV,Uv,tv,tv,uV,uv

字符串的字典顺序因字符的基本顺序不同而有所不同:

"aAbBcCdD...tTuUvV..."

  • F#:"ABC..TUV..Zabc..tuv.."

  • C#
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-06-24 05:55:12

请参阅language spec的8.15.6节。

字符串、数组和本机整数都有特殊的比较语义,如果实现了IComparable (对各种优化进行取模,会产生相同的结果),那么其他所有的东西都会被用来比较。

特别是,与大多数默认使用区域性比较的.NET不同,F#字符串在默认情况下使用序号比较。

这显然是F#和其他.NET语言之间令人困惑的不兼容性,但它确实有一些好处:

  • OCAML compat
  • 字符串和字符比较在
    • C# OCAML中保持一致

编辑:

注意,声明"F#使用区分大小写的字符串比较“是有误导性的(虽然不是不正确的)。F#使用序号比较,这比区分大小写更严格。

代码语言:javascript
复制
// case-sensitive comparison
StringComparer.InvariantCulture.Compare("[", "A") // -1
StringComparer.InvariantCulture.Compare("[", "a") // -1

// ordinal comparison
// (recall, '[' lands between upper- and lower-case chars in the ASCII table)
compare "[" "A"  // 26
compare "[" "a"  // -6
票数 6
EN

Stack Overflow用户

发布于 2015-06-23 17:49:58

不同的库对字符串进行不同的默认比较操作。F#严格默认区分大小写,而LINQ不区分大小写。

List.sortWithArray.sortWith都允许指定比较。Enumerable.OrderBy的过载也是如此。

然而,Seq模块似乎没有对应的模块(并且在4.6中没有添加一个模块)。

具体问题:

排序逻辑上的差异有没有潜在的原因?

两种排序都是有效的。在英语中,不敏感似乎更自然,因为这是我们习惯的。但这并不能让它变得更正确。

在我的情况下,解决这个“问题”的推荐方法是什么?

明确说明这种比较。

是特定于字符串的现象,还是它也适用于其他.NET类型?

char也会受到影响。以及存在多于一种可能排序的任何其他类型(例如,A People类型:您可以根据具体要求按姓名或出生日期排序)。

票数 6
EN

Stack Overflow用户

发布于 2015-06-24 01:04:24

这与C#与F#,甚至与IComparable无关,而只是由于库中不同的排序实现。

TL;DR;版本是对字符串进行排序可以得到不同的结果:

代码语言:javascript
复制
"tv" < "TV"  // false
"tv".CompareTo("TV")  // -1 => implies "tv" *is* smaller than "TV"

或者更清楚的是:

代码语言:javascript
复制
"a" < "A"  // false
"a".CompareTo("A")  // -1 => implies "a" is smaller than "A"

这是因为CompareTo使用当前的区域性(see MSDN)

我们可以通过一些不同的例子来看看这是如何在实践中发挥作用的。

如果我们使用标准的F#排序,我们会得到大写优先的结果:

代码语言:javascript
复制
let strings = [ "UV"; "Uv"; "uV"; "uv"; "Tv"; "TV"; "tv"; "tV" ]

strings |> List.sort 
// ["TV"; "Tv"; "UV"; "Uv"; "tV"; "tv"; "uV"; "uv"]

即使我们对IComparable进行强制转换,也会得到相同的结果:

代码语言:javascript
复制
strings |> Seq.cast<IComparable> |> Seq.sort |> Seq.toList
// ["TV"; "Tv"; "UV"; "Uv"; "tV"; "tv"; "uV"; "uv"]

另一方面,如果我们从F#使用Linq,我们会得到与C#代码相同的结果:

代码语言:javascript
复制
open System.Linq
strings.OrderBy(fun s -> s).ToArray()
// [|"tv"; "tV"; "Tv"; "TV"; "uv"; "uV"; "Uv"; "UV"|]

根据MSDN的说法,OrderBy方法“使用缺省的比较器缺省值来比较键”。

默认情况下,F#库不使用Comparer,但我们可以使用sortWith

代码语言:javascript
复制
open System.Collections.Generic
let comparer = Comparer<string>.Default

现在,当我们进行这种排序时,我们得到了与LINQ OrderBy相同的结果

代码语言:javascript
复制
strings |> List.sortWith (fun x y -> comparer.Compare(x,y))
// ["tv"; "tV"; "Tv"; "TV"; "uv"; "uV"; "Uv"; "UV"]

或者,我们可以使用内置的CompareTo函数,它会产生相同的结果:

代码语言:javascript
复制
strings |> List.sortWith (fun x y -> x.CompareTo(y))
// ["tv"; "tV"; "Tv"; "TV"; "uv"; "uV"; "Uv"; "UV"] 

这个故事的寓意:如果你关心排序,总是指定要使用的具体比较!

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30999018

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档