繁体   English   中英

Haskell中Python Groupby的模拟

[英]Analog of python groupby in haskell

在python中有groupby函数。

它的类型可以用haskell这样的groupby :: a->b->[a]->[(b, [a])]表示groupby :: a->b->[a]->[(b, [a])]因为它需要对数据进行排序,所以我们可以认为它的运行时间为O(n*log(n))

我可能不是唯一对此不满意的人,所以我找到了这个 。groupby的实现需要在输入序列上进行两次传递。 因此,我认为它的运行时间为O(n) ,但是正如文档中所说的那样,它并不是很懒惰,因为如果您不向其传递密钥,则需要进行传递序列以从中收集所有唯一密钥。项目。

所以我以雷蒙德·赫特格为例

一定会有更好的办法!

所以我写了这个

from collections import defaultdict, deque


def groupby(sequence, key=lambda x: x):
    buffers = defaultdict(deque)
    kvs = ((key(item), item) for item in sequence)
    seen_keys = set()
    def subseq(k):
        while True:
            buffered = buffers[k]
            if buffered:
                yield buffered.popleft()
            else:
                next_key, value = next(kvs)
                buffers[next_key].append(value)
    while True:
        try:
            k, value = next(kvs)
        except StopIteration:
            for bk, group in buffers.items():
                if group and bk not in seen_keys:
                    yield (bk, group)
            raise StopIteration()
        else:
            buffers[k].append(value)
        if k not in seen_keys:
            seen_keys.add(k)
            yield k, subseq(k)

如果您不熟悉python,则此想法非常简单。 创建key -> queue of elements可变字典尝试获取序列的下一个元素及其键值。 如果序列不为空,则根据其键将该值添加到组队列中。 如果我们没有看到此密钥产生一对(密钥,可迭代组),则后一个将从缓冲区或序列中获取密钥。 如果我们已经看到此键,则不执行任何操作并循环。

如果序列结束,则意味着其所有元素已经放入缓冲区(并且可能已消耗)。 如果缓冲区不为空,我们将对其进行迭代并产生重命名(键,可迭代)对。

我已经对其和它的作品进行了单元测试。 而且它确实是懒惰的(意味着在消费者没有要求之前它不会从序列中获取任何值),并且它的运行时间应该为O(n)

我试图对此功能进行haskell模拟,但没有发现任何东西。

可以在haskell中写这样的东西吗? 如果是这样,请显示解决方案,否则请说明原因。

如果我理解正确,则您想要的类型是

(a -> k) -> [a] -> [(k, [a])]

即,给定键功能和项目列表,按键将项目分组。

在Haskell中,有一个库函数groupBy可以执行类似的操作。 假定您有一个排序列表,并将满足布尔条件的项目分组到子列表中。 我们可以用它来做您想要的:

import Data.List
import Data.Ord

groupByKey :: (a -> k) -> [a] -> [(k, [a])]
groupByKey keyF xs = map getResult groups
   where
      keyPairs = map (\v -> (keyF v, v)) xs
      groups = groupBy (\v1 v2 -> fst v1 == fst v2) 
                  $ sortBy (comparing fst) keyPairs
      getResult xs = (fst $ head xs, map snd xs)

keyPairs是参数中每个元素的对(key, value) groups首先使用sortBy分类为键顺序,然后将结果分组到共享相同键的子列表中。 getResult将一个子列表转换为包含键(从head元素获取)和原始值列表的对。 我们可以安全地使用head因为groupBy永远不会给出空的子列表。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM