【问题标题】:grouping a list of lists by their first element [duplicate]按列表的第一个元素对列表进行分组[重复]
【发布时间】:2018-12-10 22:03:35
【问题描述】:

我想在业余时间通过解决 ProjectEuler 问题来学习 Haskell,当我遇到问题 5 时,我最终尝试按列表的第一个元素对列表进行分组。以下是我想要的行为示例:

输入:

[[2], [3], [2, 2], [5], [7], [3, 3]]`

输出:

[[[2], [2, 2]], [[3], [3, 3]], [[5]], [[7]]]

为此,我编写了以下代码

import Data.List (groupBy)

factors = [[2], [3], [2, 2], [5], [7], [3, 3]]
groupedFactors = 
    let comp x y = (head x) == (head y)
    in groupBy comp factors

但是,上面代码的结果是下面的列表

[[[2]],[[3]],[[2,2]],[[5]],[[7]],[[3,3]]]

我尝试调试这个,所以我在 GHCI 中编写了以下代码:

factors = [[2], [3], [2, 2], [5], [7], [3, 3]]
comp x y = (head x) == (head y)
comp (factors!!0) (factors!!2)

产生True,比较第四个元素产生False,正如预期的那样。

最后我想说的是,我当然可以用另一种方法解决手头的问题,但我很想知道这里发生了什么。对我来说,理解为什么会出现这种行为比如何解决它更重要(尽管我也不会对解决方案说不)。

【问题讨论】:

  • 请注意,Project Euler 的目的是鼓励人们思考和学习,因此发布解决方案或工作代码会使这个过程变得毫无用处。
  • 作为提示,groupBy 函数将元素分组在一行中。所以groupBy (==) [1,1, 2,3] 返回[[1,1], [2], [3]]groupBy (==) [1, 2, 1,3] 返回[[1], [2], [1], [3]]

标签: haskell group-by


【解决方案1】:

首先让我们注意,使用on combinator 不是写你明确命名的comp,而是更容易:

Prelude Data.List Data.Function> groupBy ((==)`on`head) [[2], [2,2], [3], [3,5]] 
[[[2],[2,2]],[[3],[3,5]]]

现在,group* 函数始终只将列表中已经相邻的元素聚集在一起。

Prelude Data.List Data.Function> group "aaabac"
["aaa","b","a","c"]

原因是这可以在 O(n) 时间和懒惰地完成,而从列表中的任何地方收集元素只给定一个相等谓词将是 O (n²)。为了使这个高效,首先排序列表的常用方法,它只在O(n·log n) 时间。

Prelude Data.List Data.Function> group $ sort "aaabac"
["aaaa","b","c"]

所以对于你的例子,这将是

> groupBy ((==)`on`head) $ sortBy (compare`on`head) [[2], [3], [2, 2], [5], [7], [3, 3]]
[[[2],[2,2]],[[3],[3,3]],[[5]],[[7]]]

这可以通过使用 sortOn 函数来简化,该函数已经内置了预映射:

> groupBy ((==)`on`head) $ sortOn head [[2], [3], [2, 2], [5], [7], [3, 3]]
[[[2],[2,2]],[[3],[3,3]],[[5]],[[7]]]

使用extra 包中的groupSortOn 甚至更短,它集所有功能于一身:

Prelude Data.List.Extra> groupSortOn head [[2], [3], [2, 2], [5], [7], [3, 3]]
[[[2],[2,2]],[[3],[3,3]],[[5]],[[7]]]

由于我通常不鼓励使用 head,因此建议您考虑使用 take 1 来代替。

【讨论】:

    猜你喜欢
    • 2016-03-17
    • 2021-04-29
    • 1970-01-01
    • 2012-03-13
    • 2019-11-25
    • 2017-03-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多