天儿真好!
所以我有一个函数,它从两个列表中获取元素,第一个是标准列表格式,第二个是列表列表,内部列表包含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元组的列表列表通常有点困难,链(链( ))只是扁平化(进入传统的单个元素列表)第二个列表与前面提到的'奇怪的格式'。其余的代码只是从函数的输出重建新列表到原始格式,该函数已经是扁平形式。
我遇到的问题是这样的:
我希望输出的大小和格式与原始的“第二”列表完全相同。如果两个列表都为空,我希望返回空列表。如果第一个列表为空,我想要返回原始的第二个列表。如果第二个列表为空,我想要返回空列表。
如果第一个列表比第二个列表短,我想运行该函数,但是可以在两个列表之间匹配元素,然后第二个列表的“多余”保持不变。
如果第二个列表比第一个列表短,我希望函数在第二个列表中运行多个元素,然后忽略列表1中的“多余”元素,从而仍然输出一个新的列表具有与原始第二个列表相同的尺寸和格式。
我的问题是,我不知道如何在我的代码中实现这些小细微差别。任何帮助将不胜感激。
干杯, 詹姆斯
答案 0 :(得分:0)
你可以填充第一个列表,其中没有足够长的时间,并将它修剪得太长了。
然后只执行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
答案 1 :(得分: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]]]
答案 2 :(得分:0)
如果我了解了所有要求,我认为这可以做你想要的一切。与您的代码的主要区别在于,它还使用izip_longest()
中的itertools
和自定义fillvalue
,而不是普通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