f#: Seq时不正确的结果.groupBy对序列进行分组

  • 本文关键字:groupBy Seq 不正确 结果 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"])]

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>的别名-一个对象。两个对象彼此不相等,除非它们引用相同的地址;它们有引用相等

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

最新更新