在将列表列表合并为python中的单个列表时删除重复项

时间:2019-09-23 19:19:01

标签: python

所以,我有如下列表:

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']

我该怎么做?

4 个答案:

答案 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. 基准数据1:

     data1 = [['foo', 'bar'],['foo', 'two']] * 1000000
    
    1. @Massifoxitertools.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) 
      
    2. @Maratdedup解决方案

      %%timeit
      list(dedup(chain.from_iterable(zip_longest(*data1))))
      # 579 ms ± 116 ms per loop (mean ± std. dev. of 7 runs, 1 loop each) 
      
    3. @Alexanderzip_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. 基准数据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)]
    
    1. @Massifoxitertools.chain.from_iterable解决方案

      %%timeit
      list(chain.from_iterable(data2))
      # 241 ms ± 20 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
      
    2. @Maratdedup解决方案

      %%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)
      
    3. @Alexanderzip_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)
      

基于sumCounter的实现是     决定性地降低效率,并且已经花费了数十秒钟     基准[['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()