当序列中的Seq.groupBy分组时,F#:结果不正确?

时间:2015-10-23 12:53:09

标签: f#

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"])]

3 个答案:

答案 0 :(得分:2)

如果你试图检查fsi这个平等:

seq { yield 1; yield 2 } = seq { yield 1; yield 2 }
你会得到假的。列表的比较正如您所期望的那样工作。

您需要做的就是将序列转换为列表或保留数组

|> Seq.groupBy (fun word -> word |> Seq.sort |> List.ofSeq)

答案 1 :(得分:2)

Seq.sort返回't seq类型的值,这是IEnumerable<'t>的同义词。现在,IEnumerable<'t>不是结构上可比较的类型,因此对来自Seq.sort的调用产生的结果无法匹配和分组。

您可以添加|> List.ofSeq|> Array.ofSeq以将't seq'转换为't list't [],这两者在结构上具有可比性。

答案 2 :(得分:2)

只需添加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>的别名 - 对象。两个对象彼此不相等,除非它们引用相同的地址;他们有参考平等

通过将它们转换为列表,您可以获得预期的结构平等