0

天!

所以我有一个函数从两个列表中获取元素,第一个是标准列表格式,第二个是列表列表,内部列表包含 3 元组形式的元素。我的输出是第二个列表格式的新列表,在相同数量的内部列表中包含相同数量的元素,其中一些值由于通过函数而略有调整。

这是一个示例代码和一个示例函数,其中链是从 itertools 导入的。第一个是一些列表,例如,[0,1,2,3,1,5,6,7,1,2,3,5,1,1,2,3,5,6]而第二个是一些列表,例如[[(13,12,32),(11,444,25)],[(312,443,12),(123,4,123)],[(545,541,1),(561,112,560)]]

def add(x, y):
    return x + y 

foo = [add(x, y) for x, y in zip(first, chain(*(chain(*second))))]
bar = [foo[i:i+3] for i in range(0, len(foo), 3)]
second = [bar[i:i+2]  for i in range(0, len(foo) / 3, 2)]

* *注意: Chain(chain()) 部分用于以下目的:因为处理包含 3 元组的列表列表通常有点困难,所以 chain(chain()) 只是扁平化(变成传统列表单个元素)具有上述“奇怪格式”的第二个列表。其余的代码只是从函数的输出中将新列表重建为原始格式,该输出已经是扁平化的形式。

我遇到的问题是这样的:

我希望输出的大小和格式与原始“第二个”列表完全相同。如果两个列表都是空的,我希望返回空列表。如果第一个列表为空,我希望返回原始的第二个列表。如果第二个列表为空,我希望返回空列表。

如果第一个列表比第二个列表短,我希望函数运行,但是两个列表之间的元素可以匹配,那么第二个列表的“多余”保持不变。

如果第二个列表比第一个列表短,我希望该函数运行第二个列表中有多少元素,然后忽略列表 1 中的“多余”元素,因此仍然输出具有相同的新列表尺寸和格式作为原始的第二个列表。

我的问题是,我不知道如何在我的代码中实现这些细微差别。任何帮助,将不胜感激。

干杯,詹姆斯

4

3 回答 3

0

因为zip只压缩到两个列表中较小的一个,所以这里用处不大。您可以创建自己的算法,以您指定的方式将函数应用于两个列表:

from itertools import *


def flatten(seq):
    return list(chain(*(chain(*seq))))

def special_apply(a,b, func):
    """
    applies a two argument function to the given flat lists.
    The result will have the same size as the second list, even if the first list is shorter.
    """
    result = []
    for i in range(len(b)):
        if i < len(a):
            element = func(a[i], b[i])
        #if a ran out of elements, just supply an unmodified element of b
        else:
            element = b[i]
        result.append(element)
    return result

def add(x,y):
    return x+y

a = [1,1,1] 
b = [[(13,12,32),(11,444,25)],[(312,443,12),(123,4,123)],[(545,541,1),(561,112,560)]]
foo = special_apply(a, flatten(b), add)
bar = [foo[i:i+3] for i in range(0, len(foo), 3)]
result = [bar[i:i+2]  for i in range(0, len(foo) / 3, 2)]
print result

结果:

[[[14, 13, 33], [11, 444, 25]], [[312, 443, 12], [123, 4, 123]], [[545, 541, 1], [561, 112, 560]]]
于 2013-10-01T14:49:06.653 回答
0

你能用 None 填充第一个列表不够长的地方,然后修剪它太长的地方。

然后只执行 x 不是 None 的函数,否则返回 y

我试图编写一个示例

from itertools import chain

first = [0, 1, 2, 3, 1, 5, 6, 7, 1, 2, 3, 5, 1, 1, 2, 3, 5, 6]
second = [
    [(13, 12, 32), (11, 444, 25)],
    [(312, 443, 12), (123, 4, 123)],
    [(545, 541, 1), (561, 112, 560)],
    [(13, 12, 32), (11, 444, 25)],
    [(312, 443, 12), (123, 4, 123)],
    [(545, 541, 1), (561, 112, 560)],
]

def add(x, y):
    return x + y 


def pad(list,length):
    for i in range(length-len(list)):
        list.append(None)
    return list[0:length]


first = pad(first,len(list(chain(*(chain(*second))) )))
# There is probably a better way to achieve this
foo = [add(x, y) if x else y for x, y in zip(first, chain(*(chain(*second))))]
bar = [foo[i:i+3] for i in range(0, len(foo), 3)]
second = [bar[i:i+2]  for i in range(0, len(foo) / 3, 2)]
print second
于 2013-10-01T14:46:10.617 回答
0

如果我了解所有要求,我认为这可以满足您的所有要求。与您的代码的主要区别在于它还使用izip_longest()itertools定义fillvalue而不是普通的 from zip()。它还只是在开始时检查涉及空输入列表的特殊情况,这似乎比尝试设计列表推导或任何处理它们的方法更容易。

from itertools import chain, izip_longest

def add(x, y):
    return x + y

def func(first, second):
    if not first: return second
    if not second: return []
    second = chain(*(chain(*second)))  # flatten
    foo = [add(x, y) for x, y in izip_longest(first, second, fillvalue=0)]
    bar = [tuple(foo[i:i+3]) for i in range(0, len(foo), 3)]
    return [bar[i:i+2]  for i in range(0, len(foo) / 3, 2)]

if __name__ == '__main__':
    first = [
        0, 1, 2,  3, 1, 5,
        6, 7, 1,  2, 3, 5,
        1, 1, 2,  3, 5, 6]
    second = [
        [(13, 12, 32), (11, 444, 25)],      [(312, 443, 12), (123, 4, 123)],
        [(545, 541, 1), (561, 112, 560)],   [(13, 12, 32), (11, 444, 25)],
        [(312, 443, 12), (123, 4, 123)],    [(545, 541, 1), (561, 112, 560)],
    ]

    print func(first, second)
    print
    print func(first[:-1], second) # 1st shorter, as many as poss, rest unchanged
    print
    print func(first, second[:-1]) # 2nd shorter, do only as many as in second
于 2013-10-01T17:17:17.457 回答