按条件将列表拆分为块

时间:2013-08-27 02:31:36

标签: python list grouping list-comprehension itertools

我有一个列表:

["asdf-1-bhd","uuu-2-ggg","asdf-2-bhd","uuu-1-ggg","asdf-3-bhd"]

我想在删除号码后拆分成两个元素相等的组:

"asdf-1-bhd", "asdf-2-bhd", "asdf-3-bhd"
"uuu-2-ggg" , uuu-1-ggg"

我一直在使用itertools.groupby

for key, group in itertools.groupby(elements, key= lambda x : removeIndexNumber(x)):

但是当要分组的元素不连续时,这不起作用。

我考虑过使用列表推导,但这似乎是不可能的,因为组的数量不固定。

TL; DR:

我想分组,两个问题:

  1. 我不知道我将获得的块数
  2. 我将被分组为块的元素可能不是连续的

2 个答案:

答案 0 :(得分:3)

你为什么不考虑它有点不同。您可以将每个地图映射到一个字典:

import re
from collections import defaultdict
regex = re.compile('([a-z]+\-)\d(\-[a-z]+)')

t = ["asdf-1-bhd","uuu-2-ggg","asdf-2-bhd","uuu-1-ggg","asdf-3-bhd"]

maps = defaultdict(list)

for x in t:
    parts = regex.match(x).groups()
    maps[parts[0]+parts[1]].append(x)

输出:

[['asdf-1-bhd', 'asdf-2-bhd', 'asdf-3-bhd'], ['uuu-2-ggg', 'uuu-1-ggg']]

这非常快,因为您不必将一件事与另一件事进行比较。

编辑:

以不同的方式思考

您最初的方法是迭代每个项目并将它们相互比较。这是过于复杂和不必要的。

让我们考虑一下我的代码。首先它得到了精简版:

"asdf-1-bhd" -> "asdf--bhd"
"uuu-2-ggg" -> "uuu--ggg"
"asdf-2-bhd" -> "asdf--bhd"
"uuu-1-ggg" -> "uuu--ggg"
"asdf-3-bhd" -> "asdf--bhd"

您已经可以开始查看群组了,我们还没有比较任何内容!

我们现在进行一种反向映射。我们把所有东西都放在右边,把它作为一个键,左边的任何东西放在一个列表中,该列表由左边的值映射:

'asdf--bhd' -> ['asdf-1-bhd', 'asdf-2-bhd', 'asdf-3-bhd']
'uuu--ggg' -> ['uuu-2-ggg', 'uuu-1-ggg']

我们的组由他们的公共计算值(键)定义。这适用于任何数量的元素和组。

答案 1 :(得分:0)

好的,简单的解决方案(这里一定为时已晚):

使用itertools.groupby,但首先sort列表。

至于上面给出的例子:

elements = ["asdf-1-bhd","uuu-2-ggg","asdf-2-bhd","uuu-1-ggg","asdf-3-bhd"]
elemens.sort(key = lambda  x : removeIndex(x))
for key, group in itertools.groupby(elements, key= lambda x : removeIndexNumber(x)):
     for element in group:
         # do stuff

如您所见,排序条件与分组相同。这样,最终必须分组的元素首先被置于连续的顺序中。完成此操作后,itertools.groupy可以正常运行。