Steven Proctor贴了一个Ruby的Enumerable#group_by
的例子:
["tar", "rat", "bar", "rob", "art", "orb"].group_by {|word| word.chars.sort}
# => {["a", "r", "t"]=>["tar", "rat", "art"],
# ["a", "b", "r"]=>["bar"],
# ["b", "o", "r"]=>["rob", "orb"]}
我决定在f#中做同样的事情:
let grouped = seq ["tar";"rat";"bar";"rob";"art";"orb"]
|> Seq.groupBy (fun word -> word |> Seq.sort)
…但是我没有得到与Ruby程序相同的结果:
seq
[(seq ['a'; 'r'; 't'], seq ["tar"]);
(seq ['a'; 'r'; 't'], seq ["rat"]);
(seq ['a'; 'b'; 'r'], seq ["bar"]);
(seq ['b'; 'o'; 'r'], seq ["rob"]);
(seq ['a'; 'r'; 't'], seq ["art"]);
(seq ['b'; 'o'; 'r'], seq ["orb"])]
为什么Seq.groupBy
不组?根据FSI,两个等价序列实际上是相等的:
> let a = seq ['a'; 'r'; 't'];;
> let b = seq ['a'; 'r'; 't'];;
> a = b;;
// val it : bool = true
为什么Seq.groupBy
不返回以下内容?
seq
[(seq ['a'; 'r'; 't'], seq ["tar"; "rat"; "art"]);
(seq ['a'; 'b'; 'r'], seq ["bar"]);
(seq ['b'; 'o'; 'r'], seq ["rob"; "orb"])]
Seq.sort
返回't seq
类型的值,这是IEnumerable<'t>
的同义词。现在,IEnumerable<'t>
不是一个结构上可比较的类型,因此调用Seq.sort
产生的结果不能通过。
您可以添加|> List.ofSeq
或|> Array.ofSeq
将't seq'
转换为't list
或't []
,它们在结构上是可比较的。
如果你想检查fsi这个等式:
seq { yield 1; yield 2 } = seq { yield 1; yield 2 }
你会得到false。列表的比较工作如你所料。
你所需要做的就是将你的序列转换为列表或者继续使用数组
|> Seq.groupBy (fun word -> word |> Seq.sort |> List.ofSeq)
添加Seq.toList
:
let grouped =
seq ["tar";"rat";"bar";"rob";"art";"orb"]
|> Seq.groupBy (fun word -> word |> Seq.sort |> Seq.toList)
生产:
> grouped |> Seq.toList;;
val it : (char list * seq<string>) list =
[(['a'; 'r'; 't'], seq ["tar"; "rat"; "art"]);
(['a'; 'b'; 'r'], seq ["bar"]);
(['b'; 'o'; 'r'], seq ["rob"; "orb"])]
它没有像OP中给出的那样工作的原因是因为Seq.sort
返回char seq
,这是IEnumerable<char>
的别名-一个对象。两个对象彼此不相等,除非它们引用相同的地址;它们有引用相等。
通过将它们转换为列表,您可以获得预期的结构相等。