我有一个问题,我需要将一些列表(2个或更多)组合成一个可迭代的列表。问题是,组成可迭代的列表不断更新,我希望我的iterable能够在没有任何额外工作的情况下获得这些更改。
仅仅组合列表不起作用,因为向列表添加列表会生成新列表。
list_a = ['foo', 'bar']
list_b = ['abc']
list_c = list_a + list_b
list_a.append('ttt')
print(list_c)
# Result: ['foo', 'bar', 'abc']
我可以将列表添加到列表中以制作列表列表,并且这样做有效,但是解压缩会使我的生产代码逻辑太复杂而无法生存。
list_a = ['foo', 'bar']
list_b = ['abc']
list_c = [list_a, list_b]
list_a.append('ttt')
print(list_c)
# Result: [['foo', 'bar', 'ttt'], ['abc']]
我喜欢itertools.chain的想法,因为它让我成为了那里的一部分但我只能在我丢失对原始列表的引用之前迭代一次列表。
import itertools
list_a = ['foo', 'bar']
list_b = ['abc']
iter_c = itertools.chain(list_a, list_b)
list_a.append('ttt')
for item in iter_c:
print(item) # Works fine here
for item in iter_c:
print(item) # The iterable was exhausted - this doesn't work anymore
您可以将链转换为列表,但是一旦您执行了list_a的修改就不会继续。
import itertools
list_a = ['foo', 'bar']
list_b = ['abc']
iter_c = itertools.chain(list_a, list_b)
list_a.append('ttt')
list_c = list(iter_c)
for item in list_c:
print(item) # Works fine here
for item in list_c:
print(item) # Now works fine here, too
list_a.append('zzz') # This won't get added to our chain
print(list_c)
# Result: ['foo', 'bar', 'ttt', 'abc']
我建立了一个hacky课程来做我想做的事,但我对它非常不满意。
import collections
import uuid
class IterGroup(object):
def __init__(self):
super(IterGroup, self).__init__()
self._data = collections.OrderedDict()
def append(self, item):
# The key doesn't matter as long as it's unique. The key is ignored.
self._data[str(uuid.uuid4())] = item
def __iter__(self):
for items in self._data.values():
for item in items:
yield item
list_a = ['foo', 'bar']
list_b = ['abc']
list_c = IterGroup() # Not really a list but just go with it
list_c.append(list_a)
list_c.append(list_b)
list_a.append('ttt')
for item in list_c:
print(item)
list_a.append('zzz')
for item in list_c:
print(item)
# Prints ['foo', 'bar', 'ttt', 'zzz', 'abc']
所以我对所需解决方案的标准是
有没有人有这个问题的清洁解决方案?
答案 0 :(得分:3)
我不喜欢'我认为有一种方法可以使用自定义类来解决此问题,但我不明白为什么该类应该扩展OrderedDict
;只需实施__iter__
和__getitem__
方法即可。你可以尝试这样的事情。
class Multilistview:
def __init__(self, *lists):
self.lists = lists
def __iter__(self):
return itertools.chain.from_iterable(self.lists)
def __getitem__(self, idx):
if isinstance(idx, slice):
return list(itertools.islice(self, idx.start, idx.stop, idx.step))
else:
for i, x in enumerate(self):
if i == idx:
return x
或者更简单,但每次要求提供项目时,这将实现整个列表:
def __getitem__(self, idx):
return list(self)[idx]
(您还可以通过检查每个项目的长度来确定__getitem__
更高效,以确定要使用的列表以及该列表中的"更正的"索引。)
实施例
list_a = ['foo', 'bar']
list_b = ['abc']
list_c = Multilistview(list_a, list_b)
for x in list_c:
print(x)
# foo
# bar
# abc
list_a.append('blub')
list_b[:] = [1,2,3]
print(list(list_c))
# ['foo', 'bar', 'blub', 1, 2, 3]
print(list_c[4])
# 2
print(list_c[2:5])
# ['blub', 1, 2]
答案 1 :(得分:1)
具体 - 两个清单:
def f(l1, l2): return lambda: l1 + l2
L1 = [1, 2, 3]
L2 = [4, 5]
newl = f(L1, L2)
print(newl())
L2.append(6)
print(newl())
更一般 - 任意数量的列表:
def f(*L):
def g():
out = []
for li in L:
out += li
return out
return g
L1 = [1,2]
L2 = [3,4]
L3 = [5]
newl = f(L1,L2,L3)
print(newl())
L3.append(6)
print(newl())
更通用 - 任何可变迭代器,任何组合:
def f(combine, *iters): return lambda: combine(*iters)
def makelist(*L):
out = []
for li in L:
out += li
return out
def makegenerator(*L):
for li in L:
for i in li:
yield i
def makedict(*D):
out = dict()
for di in D:
for key in di:
out[key] = di.get(key)
return out
def ListsToList(*L): return f(makelist, *L)
def ListsToGenerator(*L): return f(makegenerator, *L)
def DictsToDict(*D): return f(makedict, *D)
L1 = [1,2]
L2 = [3,4]
L3 = [5]
newl = ListsToList(L1,L2,L3)
newg = ListsToGenerator(L1,L2,L3)
L3.append(7)
print(newl())
print([i for i in newg()])
D1 = {"x": 1, "y": 2}
D2 = {"a": 5, "b": 10}
newd = DictsToDict(D1,D2)
D2["c"] = 15
print(newd())