【问题标题】:How to divide a list into a list of smaller lists based on a predicate?如何根据谓词将列表划分为较小列表的列表?
【发布时间】:2017-08-07 15:06:35
【问题描述】:

假设我有一个这样的列表:

[('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]

我想把它转换成这样的列表:

[ [('Yadda', 5), ('Yadda', 9)], [('Blah', 12), ('Blah', 2), ('Blah', 4)] ]

假设列表是按照应该拆分的谓词排序的 -

这样做的 Pythonic 方式是什么?

有没有什么功能可以做到这一点还是我必须自己写?

【问题讨论】:

标签: python list


【解决方案1】:

您可以使用itertools.groupby

from itertools import groupby

l = [('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]

l.sort(key=lambda item: item[0])

result = [list(group) for _, group in groupby(l, key=lambda item: item[0])]

【讨论】:

  • 值得一提的是,仅当您希望将其作为列表时才需要列表理解。 groupby 自己返回一个迭代器,所以如果你所做的只是迭代,那就足够了。
  • key=operator.itemgetter(0)
  • @StevenRumbalski 是的,operator.itemgetter 没问题。我觉得使用 lambda 函数更容易理解,关键是一个参数函数。
  • groupby 只对相邻的元素进行分组!这会导致 [('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4), ('Yadda', 5)] 等输入的错误输出
  • @KeerthanaPrabhakaran 是的,在测试您提供的列表之后。我们应该在groupby之前排序。
【解决方案2】:

itertools 的 Groupby 对相邻元素进行分组。

>>> from itertools import groupby
>>> l = [('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]
>>> print [list(group) for _, group in groupby(l, key=lambda item: item[0])]
[[('Yadda', 5), ('Yadda', 9)], [('Blah', 12), ('Blah', 2), ('Blah', 4)]]
>>>
>>> #if the list is not sorted!     
>>> l2 = [('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4), ('Yadda', 5)]
>>> print [list(group) for _, group in groupby(l2, key=lambda item: item[0])]
[[('Yadda', 9)], [('Blah', 12), ('Blah', 2), ('Blah', 4)], [('Yadda', 5)]]
  • 在继续之前对列表进行排序很重要!

所以排序后,

>>> l2 = [('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4), ('Yadda', 5)]
>>> get_first=key=lambda item: item[0]
>>> print [list(group) for _, group in groupby(sorted(l2,key=get_first), get_first)]
[[('Blah', 12), ('Blah', 2), ('Blah', 4)], [('Yadda', 5), ('Yadda', 9)]]
  • 您也可以使用过滤器!

作为,

>>> l=[('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]
>>> s=set(map(lambda item: item[0],l))
>>> print [filter(lambda x:name in x,l) for name in s]
[[('Blah', 12), ('Blah', 2), ('Blah', 4)], [('Yadda', 5), ('Yadda', 9)]]
  • 您也可以使用 itemgetter,

也就是说,

>>> l=[('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]
>>> from operator import itemgetter
>>> s=set(map(itemgetter(0),l))
>>> print [filter(lambda x:name in x,l) for name in s]
[[('Blah', 12), ('Blah', 2), ('Blah', 4)], [('Yadda', 5), ('Yadda', 9)]]

【讨论】:

    【解决方案3】:

    假设您根据内部列表的第一项拆分列表,我会使用字典。

    l = [('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]
    d={}
    for x in l:
      if x[0] not in d:
        d[x[0]]=[x]
      else:
        d[x[0]].append(x)
    print(d.values())
    

    【讨论】:

      【解决方案4】:

      我就是这样解决的。

      list = [('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4), ('Yadda', 5)]
      ls_set = (set([ls[0] for ls in list]))
      ls_dict = {}
      for ls in ls_set:
          ls_dict[ls] = []
      for ls in list:
          ls_dict[ls[0]].append(ls[1])
      final_list = []
      for key, value in ls_dict.items():
          a = []
          for i in value:
              a.append(tuple([key,i]))
          final_list.append(a)
      print(final_list)
      

      【讨论】:

        【解决方案5】:

        如果您想不使用任何软件包或itertools,那么这将对您有所帮助,

        >>> l = [('Yadda', 5), ('Yadda', 9), ('Blah', 12), ('Blah', 2), ('Blah', 4)]
        >>> l.sort(key= lambda x:x[1])
        >>> values = set(map(lambda x:x[0], l))
        >>> [[y for y in l if y[0]==i] for i in values]
        [[('Blah', 2), ('Blah', 4), ('Blah', 12)], [('Yadda', 5), ('Yadda', 9)]]
        >>> 
        

        【讨论】:

          猜你喜欢
          • 2011-01-05
          • 1970-01-01
          • 2012-07-01
          • 1970-01-01
          • 1970-01-01
          • 2012-11-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多