[英]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.