【问题标题】:Group items of a list with a step size python?使用步长python对列表的项目进行分组?
【发布时间】:2015-12-18 15:41:44
【问题描述】:

给定一个输入列表

 l = [1 2 3 4 5 6 7 8 9 10]

组大小 grp 和 step step

grp = 3; step = 2

我想返回一个列表。注意最后的重复

1 2 3
3 4 5
5 6 7
7 8 9
9 10 1

如果

grp= 4; step = 2

输出应该是

1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10

这是我想出的代码,它不做循环的事情。 但想知道是否有更小或更简单的解决方案

def grouplist(l,grp,step):
    oplist = list()
    for x in range(0,len(l)):
        if (x+grp<len(l)):
        oplist.append(str(l[x:x+grp]))
    return oplist

【问题讨论】:

  • 对我来说这两个例子有冲突。请为 step=1 显示一个。还是应该是示例 1?
  • @Pynchia 这两个例子并不冲突。他们都有step=2,所以第二行的第一个数字应该是3
  • 为什么对于 grp 4 step 2 我们回绕到 1 而不是 10?
  • 好的,最好解释一下步骤是什么(从组开始的偏移量,我现在收集)
  • 在@wim 评论顶部为什么第二个示例中没有第五行?

标签: python list iterator


【解决方案1】:

您可以利用 xrange 或 range 中的 step 函数,具体取决于您使用的 python 版本。然后像这样以列表的长度环绕只是 mod

import sys

def grouplist(l,grp,step):
    newlist=[]
    d = len(l)
    for i in xrange(0,len(l),step):
        for j in xrange(grp):
            newlist.append(l[(i+j)%d])
            sys.stdout.write(str(l[(i+j)%d]) + ' ')
        print

l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print grouplist(l,3,2)
1 2 3 
3 4 5 
5 6 7 
7 8 9 
9 10 1 
[1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 1]

print grouplist(l,4,2)
1 2 3 4 
3 4 5 6 
5 6 7 8 
7 8 9 10 
9 10 1 2
[1, 2, 3, 4, 3, 4, 5, 6, 5, 6, 7, 8, 7, 8, 9, 10, 9, 10, 1, 2] 

【讨论】:

  • 谢谢,但我还有一个后续问题。我实际上是对字符串执行此操作,我得到的输出格式为 ['0_1_125.jpg', '0_1_126.jpg', '0_1_127.jpg'] ['0_1_126.jpg', '0_1_127.jpg', '0_1_128. jpg'] ['0_1_127.jpg', '0_1_128.jpg', '0_1_129.jpg'] 你知道我怎样才能删除 ' 和 [] 以及逗号吗??
  • @ArsenalFanatic 对我来说看起来好像是一个列表列表,您可以通过打印它们而不是打印列表本身来摆脱 ' []
【解决方案2】:
def grouplist(L, grp, step):
    starts = range(0, len(L), step)
    stops = [x + grp for x in starts]
    groups = [(L*2)[start:stop] for start, stop in zip(starts, stops)]
    return groups

def tabulate(groups):
    print '\n'.join(' '.join(map(str, row)) for row in groups)
    print

示例输出:

>>> tabulate(grouplist(range(1,11), 3, 2))
1 2 3
3 4 5
5 6 7
7 8 9
9 10 1

>>> tabulate(grouplist(range(1,11), 4, 2))
1 2 3 4
3 4 5 6
5 6 7 8
7 8 9 10
9 10 1 2

【讨论】:

    【解决方案3】:

    使用双端队列:

    from itertools import islice
    from collections import deque
    
    
    
    def grps(l, gps, stp):
        d = deque(l)
        for i in range(0, len(l), stp):
            yield list(islice(d, gps))
            d.rotate(-stp)
    

    输出:

    In [7]: l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    
    In [8]: list(grps(l, 3, 2))
    Out[8]: [[1, 2, 3], [3, 4, 5], [5, 6, 7], [7, 8, 9], [9, 10, 1]]
    
    In [9]: list(grps(l, 4, 2))
    Out[9]: [[1, 2, 3, 4], [3, 4, 5, 6], [5, 6, 7, 8], [7, 8, 9, 10], [9, 10, 1, 2]]
    

    你也可以加入 yield islice 对象并决定你想在外面做什么:

    def grps(l, gps, stp):
        d =  deque(l)
        for i in range(0, len(l), stp):
            yield  islice(d, gps)
            d.rotate(-stp)
    

    输出:

    In [11]:     for gp in grps(l, 3,2):
       ....:             print(" ".join(map(str,gp)))
       ....:     
    1 2 3
    3 4 5
    5 6 7
    7 8 9
    9 10 1
    

    或者只是模数:

    def grps(l, gps, stp):
        ln = len(l)
        for i in range(0, len(l), stp):
            yield (l[j % ln] for j in range(i, i + gps))
    
    
    for gp in grps(l, 4, 2):
        print(" ".join(map(str, gp)))
    

    【讨论】:

    • @Padraic...我正在为您的答案而努力,但您超越了我...太棒了... :)
    • 双端队列的想法很好。
    • @PadraicCunningham...Mind 分享一些有关使用 itertools 和 collections 模块的资源...因为我一直在关注您的答案,我看到您正在使用他们的很多方法...谢谢.. :)
    【解决方案4】:
    [(l+l)[x:x+grp] for x,_ in list(enumerate(l))[::step]]
    

    在一行中完成技巧

    【讨论】:

    • 不过需要注意的是,l+l每次迭代的效率低得惊人!
    • l2 = l+l; [l2[x:x+grp] for x,_ in list(enumerate(l))[::step]] 解决问题
    【解决方案5】:

    iteration_utilities1有这种滑动窗口提取的功能successive:

    from iteration_utilities import successive
    from itertools import chain, islice, starmap
    
    def wrapped_and_grouped_with_step(seq, groupsize, step, formatting=False):
        padded = chain(seq, seq[:step-1])
        grouped = successive(padded, groupsize)
        stepped = islice(grouped, None, None, step)
        if formatting:
            inner_formatted = starmap(('{} '*groupsize).strip().format, stepped)
            outer_formatted = '\n'.join(inner_formatted)
            return outer_formatted
        else:
            return stepped
    

    将此应用于您的示例:

    >>> list(wrapped_and_grouped_with_step(l, 3, 2))
    [(1, 2, 3), (3, 4, 5), (5, 6, 7), (7, 8, 9), (9, 10, 1)]
    
    >>> list(wrapped_and_grouped_with_step(l, 4, 2))
    [(1, 2, 3, 4), (3, 4, 5, 6), (5, 6, 7, 8), (7, 8, 9, 10)]
    
    >>> print(wrapped_and_grouped_with_step(l, 3, 2, formatting=True))
    1 2 3
    3 4 5
    5 6 7
    7 8 9
    9 10 1
    
    >>> print(wrapped_and_grouped_with_step(l, 4, 2, formatting=True))
    1 2 3 4
    3 4 5 6
    5 6 7 8
    7 8 9 10
    

    该包还包括一个便利类ManyIterables

    >>> from iteration_utilities import ManyIterables
    >>> step, groupsize = 2, 4
    >>> print(ManyIterables(l, l[:step-1])
    ...       .chain()
    ...       .successive(groupsize)
    ...       [::step]
    ...       .starmap(('{} '*groupsize).strip().format)
    ...       .as_string('\n'))
    1 2 3 4
    3 4 5 6
    5 6 7 8
    7 8 9 10
    

    请注意,这些操作是基于生成器的,因此评估会推迟到您对其进行迭代(例如通过创建list)。


    请注意,我是iteration_utilities 的作者。还有其他几个包也提供类似的功能,即more-itertoolstoolz

    【讨论】:

      【解决方案6】:

      这是另一种解决方案,它在扫描列表时不使用列表中的索引。相反,它会保存遇到的要重复的元素并将它们与后面的元素连接起来。

      def grplst(l, grp, stp):
          ret = []
          saved = []
          curstp = 0
          dx = grp - stp
          for el in l:
              curstp += 1
              if curstp <= stp:
                  ret.append(el)
              else:
                  saved.append(el)
                  if curstp >= grp:
                      yield ret+saved
                      ret = saved
                      saved = []
                      curstp = dx
          yield ret+l[:dx]
      
      
      l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
      
      for g in grplst(l, 3, 2):
          print(g)
      
      for g in grplst(l, 4, 2):
          print(g)
      

      生产

      [1, 2, 3]
      [3, 4, 5]
      [5, 6, 7]
      [7, 8, 9]
      [9, 10, 1]
      
      [1, 2, 3, 4]
      [3, 4, 5, 6]
      [5, 6, 7, 8]
      [7, 8, 9, 10]
      [9, 10, 1, 2]
      

      【讨论】:

        【解决方案7】:

        从 2.5 版开始,more_itertools.windowed 支持 step 关键字。

        > pip install more_itertools
        

        应用:

        import itertools as it 
        
        import more_itertools as mit
        
        def grouplist(l, grp, step):
            """Yield a finite number of windows."""
            iterable = it.cycle(l)
            cycled_windows = mit.windowed(iterable, grp, step=step)
            last_idx = grp - 1
            for i, window in enumerate(cycled_windows):
                yield window
                if last_idx >= len(l) - 1:
                    break
                last_idx += (i * step)
        
        
        list(grouplist(l, 3, 2))
        # Out: [(1, 2, 3), (3, 4, 5), (5, 6, 7), (7, 8, 9), (9, 10, 1)]
        
        list(grouplist(l, 4, 2))
        # Out: [(1, 2, 3, 4), (3, 4, 5, 6), (5, 6, 7, 8), (7, 8, 9, 10)]
        
        list(mit.flatten(grouplist(l, 3, 2))))                  # optional
        # Out: [1, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 9, 10, 1]
        

        【讨论】:

          猜你喜欢
          • 2017-05-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-02-06
          • 1970-01-01
          • 2022-08-16
          • 2021-11-14
          • 1970-01-01
          相关资源
          最近更新 更多