(Array / List / Seq).groupBy是否维护组内的排序顺序?

时间:2015-12-01 14:01:13

标签: f#

groupBy是否保证在以下代码中保留排序顺序?

x
|> Seq.sortBy (fun (x, y) -> y)
|> Seq.groupBy (fun (x, y) -> x)

通过保留排序顺序,我的意思是我们可以保证在x的每个分组中,结果仍按y排序。

这对于简单的例子来说是正确的,

[(1, 3);(2, 1);(1, 1);(2, 3)]
|> Seq.sortBy (fun (x, y) -> y)
|> Seq.groupBy (fun (x, y) -> x)
// seq [(2, seq [(2, 1); (2, 3)]); (1, seq [(1, 1); (1, 3)])]

我想确保没有奇怪的边缘情况。

3 个答案:

答案 0 :(得分:8)

保留排序顺序是什么意思? Seq.groupBy更改了序列的类型,那么你怎么能在和 之后有意义地比较

对于xs类型的给定seq<'a * 'b>,表达式xs |> Seq.sortBy snd的类型为seq<'a * 'b>,而表达式xs |> Seq.sortBy snd |> Seq.groupBy fst的类型为{ {1}}。因此,问题的答案是还是取决于保留排序顺序的含义。

正如@Petr在评论中写道的那样,测试它很容易。如果您担心特殊情况,请使用FsCheck撰写属性,看看它是否有所说明:

seq<'a * seq<'a * 'b>>

在此属性中,我将排序顺序保留的属性解释为,如果随后连接分组序列,则会保留排序顺序。你的定义可能不同。

鉴于这个特定的定义,运行该属性清楚地表明该属性并不成立:

open FsCheck.Xunit
open Swensen.Unquote

[<Property>]
let isSortOrderPreserved (xs : (int * int) list) =
    let actual = xs |> Seq.sortBy snd |> Seq.groupBy fst

    let expected = xs |> Seq.sortBy snd |> Seq.toList
    expected =! (actual |> Seq.map snd |> Seq.concat |> Seq.toList)

我们在此处看到,如果输入为Falsifiable, after 6 tests (13 shrinks) (StdGen (1448745695,296088811)): Original: [(-3, -7); (4, -7); (4, 0); (-4, 0); (-4, 7); (3, 7); (3, -1); (-5, -1)] Shrunk: [(3, 1); (3, 0); (0, 0)] ---- Swensen.Unquote.AssertionFailedException : Test failed: [(3, 0); (0, 0); (3, 1)] = [(3, 0); (3, 1); (0, 0)] false ,则分组序列不会保留排序顺序(这对我来说并不令人惊讶)。

根据更新的问题,这里有一个检查该问题的属性:

[(3, 1); (3, 0); (0, 0)]

这个属性的确坚持:

[<Property(MaxTest = 10000)>]
let isSortOrderPreservedWithEachGroup (xs : (int * int) list) =
    let actual = xs |> Seq.sortBy snd |> Seq.groupBy fst

    let expected =
        actual
        |> Seq.map (fun (k, vals) -> k, vals |> Seq.sort |> Seq.toList)
        |> Seq.toList
    expected =!
        (actual |> Seq.map (fun (k, vals) -> k, Seq.toList vals) |> Seq.toList)

您仍应仔细考虑是否要依赖未记录的行为,因为它可能会在以后的F#版本中发生变化。就个人而言,我采纳了the Zen of Python的建议:

  

明确比隐含更好。

BTW,所有转换为F#列表的原因是因为列表具有结构上的相同性,而序列则不具备。

答案 1 :(得分:1)

文档没有明确说明(通过示例除外),但是the implementation does preserve the order of the original sequence。如果它没有:我所知道的其他语言中的等效函数,那将是非常令人惊讶的。

答案 2 :(得分:0)

谁在乎呢。而不是排序然后分组,只需分组然后排序,即使groupBy的F#实现最终改变,也能保证排序:

Virtual core keyboard