所以,我有如下列表:
data = [
['foo', 'bar'],
['one', 'two']
]
而且,我想通过在两个列表之间交替来展平这些列表。 因此,输出就像
flattened = ['foo', 'one', 'bar', 'two']
我正在使用list(chain.from_iterable(zip_longest(*data)))
效果很好。
但是,我正在尝试弄清楚如何处理要消除重复的情况。
data = [
['foo', 'bar'],
['foo', 'two']
]
我想要类似
flatted = ['foo', 'two', 'bar']
而不是['foo', 'foo', 'bar', 'two']
我该怎么做?
答案 0 :(得分:4)
使用一个集合来跟踪您已经看到的内容,这是O(1)成员资格测试。
result = []
seen = set()
for item in chain.from_iterable(zip_longest(*data)):
if item not in seen:
seen.add(item)
result.append(item)
>>> result
['foo', 'bar', 'two']
请注意,此问题讨论的是从列表中删除重复项:Removing duplicates in lists
TL; DR
对于Python 3.7+(或Cython 3.6 +):
>>> list(dict.fromkeys(chain.from_iterable(zip_longest(*data))))
['foo', 'bar', 'two']
答案 1 :(得分:0)
尝试以下代码:
list(dict.fromkeys(sum(data, [])))
编辑:
正如评论中指出的那样,sum
并不是最有效的扁平化列表方法,您可以使用itertools.chain.from_iterable
来获取扁平化列表,然后执行以下操作:
list(dict.fromkeys(chain.from_iterable(data)))
在两种情况下,输出如下:
['foo', 'bar', 'two']
下面他们建议比较主要提出的解决方案的执行时间:
基准数据1:
data1 = [['foo', 'bar'],['foo', 'two']] * 1000000
itertools.chain.from_iterable
解决方案%%timeit
list(chain.from_iterable(data1))
# 128 ms ± 11.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
dedup
解决方案%%timeit
list(dedup(chain.from_iterable(zip_longest(*data1))))
# 579 ms ± 116 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
zip_longest
解决方案%%timeit
list(dict.fromkeys(chain.from_iterable(zip_longest(*data1))))
# 456 ms ± 149 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
基准数据2:
x = 10
y = 500000
n_max = 1000
data2 = [[np.random.randint(1, n_max) for _ in range(0, x)] for _ in range(0, y)]
itertools.chain.from_iterable
解决方案%%timeit
list(chain.from_iterable(data2))
# 241 ms ± 20 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
dedup
解决方案%%timeit
list(dedup(chain.from_iterable(zip_longest(*data2))))
# 706 ms ± 18.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
zip_longest
解决方案%%timeit
list(dict.fromkeys(chain.from_iterable(zip_longest(*data2))))
# 674 ms ± 56.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
基于sum
和Counter
的实现是
决定性地降低效率,并且已经花费了数十秒钟
基准[['foo', 'bar'],['foo', 'two']] * 100k
较小的实例。
使用基准测试data1
,我提出的基于itertools.chain.from_iterable
的解决方案似乎比其他解决方案快4-5倍。
使用基准测试data2
,我提出的基于itertools.chain.from_iterable
的解决方案似乎比其他解决方案快2-3倍。
答案 2 :(得分:0)
嗯,这可能比您想要的要多一些开销,但这应该可以工作,并且可以保证与集合不同的列表顺序:
from itertools import cycle
from collections import Counter
output = []
checker = Counter()
for lst in cycle(data):
if not data:
break
while lst:
item = lst.pop(0)
if not checker[item]:
output.append(item)
checker[item] += 1
break
if not lst:
data.remove(lst)
continue
输出:
['foo', 'two', 'bar']
答案 3 :(得分:-3)
您可以创建一个集合,然后再将其转换为列表,如下所示:
l1 = ['foo', 'foo', 'bar', 'two']
l2 = list(set(l1))
它创建了第二个没有重复项的列表
如果您想保留订单,可以这样做
ordered = dict.fromkeys(l1).keys()