在for循环中对数据进行分组

时间:2012-08-06 06:11:53

标签: python loops grouping

我需要循环遍历已排序的数据集,将该排序属性的所有结果分组为块,这些块对于该属性都具有相同的值。然后我在那块结果上运行一些操作。

很抱歉这有点令人困惑,例子可能是描述我正在做的更好的方式:

我有一个像这样结构化的数据集,除了“数据”字符串实际上是对象并包含大量其他数据。

[ [1, "data1"], [1, "data2"], [2, "moredata"], [2, "stuff"], 
  [2, "things"], [2, "foo"], [3, "bar"], [4, "baz"] ]

我想要发生的是将数据分组为4个不同的函数调用:

process_data(1, ["data1", "data2"])
process_data(2, ["moredata", "stuff", "things", "foo"])
process_data(3, ["bar"])
process_data(4, ["baz"])

我最终得到的结构看起来像这样:

last_id = None
grouped_data = []

for row in dataset:
    id = row[0]
    data = row[1]

    if last_id != id:
         # we're starting a new group, process the last group
         processs_data(last_id, grouped_data)
         grouped_data = []
    last_id = id
    grouped_data.append(data)

if grouped_data:
    # we're done the loop and we still have a last group of data to process
    # if there was no data in the dataset, grouped_data will still be empty
    # so we won't accidentally process any empty data.
    process_data(last_id, grouped_data)

它有效,但看起来很笨拙。尤其需要使用last_id变量跟踪所有内容以及循环后第二次调用process_data。我想知道是否有人可以提出更优雅/更聪明的解决方案。

我选择的语言是Python,但通用解决方案很好。

3 个答案:

答案 0 :(得分:5)

itertools.groupby正是您想要的:

>>> data = [ [1, "data1"], [1, "data2"], [2, "moredata"], [2, "stuff"],
...   [2, "things"], [2, "foo"], [3, "bar"], [4, "baz"] ]
>>>
>>> from itertools import groupby
>>> from operator import itemgetter
>>>
>>> def process_data(key, keydata):
...     print key, ':', keydata
...
>>> for key,keydata in groupby(data, key=itemgetter(0)):
...   process_data(key, [d[1] for d in keydata])
...
1 : ['data1', 'data2']
2 : ['moredata', 'stuff', 'things', 'foo']
3 : ['bar']
4 : ['baz']

通过排序列表传递组,以及关于列表中每个项目内的分组内容的关键功能。你得到了(key,itemgenerator)对的生成器,如图所示传递给我的make_upata方法。

答案 1 :(得分:3)

看看itertools.groupby。请注意,这要求您的列表已根据组密钥进行排序(您的示例数据是,所以我猜它没关系。)

答案 2 :(得分:3)

您可以使用MutliDict,例如来自browniewerkzeug个包。

from brownie.datastructures import MultiDict
data = [ [1, "data1"], [1, "data2"], [2, "moredata"], [2, "stuff"], 
         [2, "things"], [2, "foo"], [3, "bar"], [4, "baz"] ]
for key, keydata in MultiDict(data).iterlists():
    process_data(key, keydata)