Python 在列表中动态生成列表元素

Python 在列表中动态生成列表元素,python,generator,sequence-generators,Python,Generator,Sequence Generators,我有一个列表,它由以下元素组成 list1 = [a1,a2,a3] 其中该列表的每个元素本身可以是一个可变大小的列表,例如 a1 = [x1,y1,z1], a2 = [w2,x2,y2,z2], a3 = [p3,r3,t3,n3] 对我来说,直接建立一个生成器,在列表1中循环,并生成每个元素的成分 array = [] for i in list1: for j in i: array.append[j] yield array 但是,有没有一

我有一个列表,它由以下元素组成

list1 = [a1,a2,a3]
其中该列表的每个元素本身可以是一个可变大小的列表,例如

a1 = [x1,y1,z1], a2 = [w2,x2,y2,z2], a3 = [p3,r3,t3,n3]
对我来说,直接建立一个生成器,在列表1中循环,并生成每个元素的成分

array = []
for i in list1:
    for j in i:
        array.append[j]
        yield array
但是,有没有一种方法可以指定数组的大小

eg—两个批次的批量

1st yield : [x1,y1]
2nd yield : [z1,w1]
3rd yield : [x2,y2]
4th yield : [z2,p3]
5th yield : [r3,t3]
6th yield : [n3]
7th yield : repeat 1st
或批量大小为4

1st yield : [x1,y1,z1,w1]
2nd yield : [x2,y2,z2,p3]
3rd yield : [r3,t3,n3]
4th yield : repeat first

对不同大小的列表执行此操作似乎很重要,每个列表中包含其他不同大小的列表。

这非常简单,实际上,使用
itertools

>>> a1 = ['x1','y1','z1']; a2 = ['w2','x2','y2','z2']; a3 = ['p3','r3','t3','n3']
>>> list1 = [a1,a2,a3]
>>> from itertools import chain, islice
>>> flatten = chain.from_iterable
>>> def slicer(seq, n):
...     it = iter(seq)
...     return lambda: list(islice(it,n))
...
>>> def my_gen(seq_seq, batchsize):
...     for batch in iter(slicer(flatten(seq_seq), batchsize), []):
...         yield batch
...
>>> list(my_gen(list1, 2))
[['x1', 'y1'], ['z1', 'w2'], ['x2', 'y2'], ['z2', 'p3'], ['r3', 't3'], ['n3']]
>>> list(my_gen(list1, 4))
[['x1', 'y1', 'z1', 'w2'], ['x2', 'y2', 'z2', 'p3'], ['r3', 't3', 'n3']]
注意,我们可以在Python 3.3+中使用来自的
yield:

>>> def my_gen(seq_seq, batchsize):
...   yield from iter(slicer(flatten(seq_seq), batchsize), [])
...
>>> list(my_gen(list1,2))
[['x1', 'y1'], ['z1', 'w2'], ['x2', 'y2'], ['z2', 'p3'], ['r3', 't3'], ['n3']]
>>> list(my_gen(list1,3))
[['x1', 'y1', 'z1'], ['w2', 'x2', 'y2'], ['z2', 'p3', 'r3'], ['t3', 'n3']]
>>> list(my_gen(list1,4))
[['x1', 'y1', 'z1', 'w2'], ['x2', 'y2', 'z2', 'p3'], ['r3', 't3', 'n3']]
>>>

您可以在这里使用
itertools
,在您的情况下,我会使用和


如果您不介意附加依赖项,也可以在此处使用(尽管它返回元组而不是列表)1:

或:


1免责声明:我是该图书馆的作者


时间:


如果将任务分为两个步骤,则这相对来说是微不足道的:

  • 将列表展平
  • 根据批大小发出块
  • 下面是一个示例实现:

    from itertools import chain
    
    def break_into_batches(items, batch_size):
        flattened = list(chain(*items))
        for i in range(0, len(flattened), batch_size):
            yield flattened[i:i+batch_size]
    

    考虑到适用于列表的以下目标

  • 产量批次,每个给定的
    大小
  • 重复此过程一定数量的
    循环
  • 可以实现以下目标:

    import more_itertools as mit
    
    
    def batch(iterable, size=2, cycles=1):
        """Yield resized batches of an iterable."""
        iterable = mit.ncycles(iterable, cycles)
        return mit.chunked(mit.flatten(iterable), size)
    
    list(batch(list1, 3))
    # [["x1", "y1", "z1"], ["w2", "x2", "y2"], ["z2", "p3", "r3"], ["t3", "n3"]]
    
    
    list(batch(list1, size=3, cycles=2))
    # [["x1", "y1", "z1"], ["w2", "x2", "y2"], ["z2", "p3", "r3"],
    #  ["t3", "n3", "x1"], ["y1", "z1", "w2"], ["x2", "y2", "z2"],
    #  ["p3", "r3", "t3"], ["n3"]]
    

    有关每个工具的详细信息,请参阅文档。

    我理解的
    list1
    仅包含其他列表是否正确?当您说
    repeat 1st
    时,是否表示要在遍历列表一次后循环该列表?比如第八个收益率:重复第二个收益率,等等?如果列表1太大而无法放入内存,如何?在我的案例中,它们实际上是我连续拍摄的图像loading@obtmind嗯,这似乎是一个完全无关的问题。保存这些信息的数据结构是什么?您正在使用列表吗?您可能需要某种数组。不管怎么说,列表的内存非常非常大,只要你能将中间的列表保存在内存中,就不难将上面的内容调整为使用这些图像的某种生成器,然后将该生成器作为
    seq\u-seq
    传递给,我建议您在答案中添加性能测试。我得到:
    %timeit列表(将\u分成批(arr,4))
    :1000个循环,每个循环的最佳时间为3:950µs,
    %timeit列表(我的第代(arr,4))
    :100个循环,每个循环的最佳时间为3:3.4 ms,以及
    %timeit列表(展平_和_批(arr,4))
    :100个循环,每个循环最好3:3.12 ms。这些测试使用arr=
    import random;[[random.randint(1100)表示范围内的i(random.randint(1100))]表示范围内的k(300)]
    很好的测试!我没有注意到你的第二个解决方案!@AGNGazer,但第二个解决方案需要一个外部库,并返回一个元组列表而不是列表列表。这就是为什么它是唯一的解决方案2。:)那么,你要么重写库以返回列表,要么我收回我的投票:)说真的,@JoelCornett确实是一个快速的解决方案“通用”解决方案。
    迭代实用程序方法
    解决方案速度更快,即使包装在
    映射(列表…)
    (返回列表列表)。然而,
    列表(链(…)有一点“问题”)
    approach-它在内存中创建一个完整的列表,而所有其他方法都是惰性的。这使得解决方案非常快,但也使得它的内存非常昂贵。
    >>> Iterable(list1).flatten().grouper(3).as_list()
    [('x1', 'y1', 'z1'), ('w2', 'x2', 'y2'), ('z2', 'p3', 'r3'), ('t3', 'n3')]
    
    >>> Iterable(list1).flatten().grouper(4).map(list).as_list()
    [['x1', 'y1', 'z1', 'w2'], ['x2', 'y2', 'z2', 'p3'], ['r3', 't3', 'n3']]
    
    from itertools import chain, islice
    flatten = chain.from_iterable
    from iteration_utilities import flatten, grouper, Iterable
    
    def slicer(seq, n):
        it = iter(seq)
        return lambda: list(islice(it,n))
    
    def my_gen(seq_seq, batchsize):
        for batch in iter(slicer(flatten(seq_seq), batchsize), []):
            yield batch
    
    def flatten_and_batch(lst, size):
        it = flatten(lst)
        while True:
            res = list(islice(it, size))
            if not res:
                break
            else:
                yield res
    
    def iteration_utilities_approach(seq, size):
        return grouper(flatten(seq), size)
    
    def partition(lst, c):
        all_elem = list(chain.from_iterable(lst))
        for k in range(0, len(all_elem), c):
            yield all_elem[k:k+c]
    
    
    def juanpa(seq, size):
        return list(my_gen(seq, size))    
    def mseifert1(seq, size):
        return list(flatten_and_batch(seq, size))   
    def mseifert2(seq, size):
        return list(iteration_utilities_approach(seq, size))   
    def JoelCornett(seq, size):
        return list(partition(seq, size))       
    
    # Timing setup
    timings = {juanpa: [], 
               mseifert1: [], 
               mseifert2: [], 
               JoelCornett: []}
    
    sizes = [2**i for i in range(1, 18, 2)]
    
    # Timing
    for size in sizes:
        print(size)
        func_input = [['x1','y1','z1']]*size
        for func in timings:
            print(str(func))
            res = %timeit -o func(func_input, 3)
            timings[func].append(res)
    
    %matplotlib notebook
    
    import matplotlib.pyplot as plt
    import numpy as np
    
    fig = plt.figure(1)
    ax = plt.subplot(111)
    
    for func in timings:
        ax.plot(sizes, 
                [time.best for time in timings[func]], 
                label=str(func.__name__))
    ax.set_xscale('log')
    ax.set_yscale('log')
    ax.set_xlabel('size')
    ax.set_ylabel('time [seconds]')
    ax.grid(which='both')
    ax.legend()
    plt.tight_layout()
    
    from itertools import chain
    
    def break_into_batches(items, batch_size):
        flattened = list(chain(*items))
        for i in range(0, len(flattened), batch_size):
            yield flattened[i:i+batch_size]
    
    import more_itertools as mit
    
    
    def batch(iterable, size=2, cycles=1):
        """Yield resized batches of an iterable."""
        iterable = mit.ncycles(iterable, cycles)
        return mit.chunked(mit.flatten(iterable), size)
    
    list(batch(list1, 3))
    # [["x1", "y1", "z1"], ["w2", "x2", "y2"], ["z2", "p3", "r3"], ["t3", "n3"]]
    
    
    list(batch(list1, size=3, cycles=2))
    # [["x1", "y1", "z1"], ["w2", "x2", "y2"], ["z2", "p3", "r3"],
    #  ["t3", "n3", "x1"], ["y1", "z1", "w2"], ["x2", "y2", "z2"],
    #  ["p3", "r3", "t3"], ["n3"]]