【问题标题】:Contrasting two sorted lists in Python对比 Python 中的两个排序列表
【发布时间】:2021-06-11 02:17:25
【问题描述】:

我有两个排序列表,我需要在每个列表中找出奇数。

目前我使用not in 的两个列表推导:

> if foo != bar:
      in_foo = [i for i in foo if i not in bar]
      in_bar = [i for i in bar if i not in foo]

但是,此方法没有利用列表的排序结构。

我可以使用带有计数器变量和递归的替代方法,但有没有更 Pythonic 的方法来做到这一点?

edit:排序输出是首选。谢谢。

【问题讨论】:

  • 您可以发布示例输入和您的预期输出吗?
  • 这里涵盖了所有可能的细节:这是否回答了您的问题? Get difference between two lists
  • 谢谢@Chris,但据我所知,这个问题涵盖了未排序的列表。我没有看到任何关于利用预排序列表的方法的真正讨论。
  • 谢谢@Chris。据我所知,该源使用非pythonic计数器+递归方法(在那里作为while循环实现)。我希望有一个更 Pythonic 的解决方案。

标签: python list sorting list-comprehension


【解决方案1】:

任何时候你有这样的事情,通常最好使用一个集合并忽略排序(由于语言开销,在 Python 中对于小列表的重要性比其他编程语言要小得多)

_foo   = set(foo)
_bar   = set(bar)
in_foo = _foo - _bar
in_bar = _bar - _foo

【讨论】:

  • 请注意,他们希望保持排序不变。
  • @SrikrishnaSharma 怎么样? sets 是无序的。
  • 好吧.. 在这种情况下,我仍然很想使用set 并在之后保留或丢弃.. 但是,他们并没有说他们想要问题中的排序输出 -正如@Selcuk 所说,sets 是无序的,因此不应假定有任何特定的顺序,包括类似于原始顺序的东西!
  • 没错,他们并没有说他们想要问题中的排序输出,但问题的标题是“对比 Python 中的两个排序列表”。有点不清楚。
  • 谢谢@ti7,我考虑过使用集合差异,但后来我必须转换为集合,然后重新排序(我需要一个排序的输出)。我不知道将一步变为三步是否比效率更昂贵。
【解决方案2】:

这是三种方法的比较。 with_intersection 方法允许在每个列表中重复值,其他两个不允许。该测试考虑了两个排序列表,每个列表都有一百万个不同的整数。

using_sorted 方法利用了两个列表都已排序且不使用集合这一事实。同时,它也是最慢、最冗长和最容易出错的。

import numpy as np # only for data generation

lst1 = np.random.randint(1, 20, 10**6).cumsum().tolist()
lst2 = np.random.randint(1, 20, 10**6).cumsum().tolist()

def with_intersection(lst1, lst2):
  common = set(lst1).intersection(lst2)
  res1 = [x for x in lst1 if x not in common]
  res2 = [x for x in lst2 if x not in common]
  return res1, res2

def set_then_sort(foo, bar):
  _foo   = set(foo)
  _bar   = set(bar)
  in_foo = _foo - _bar
  in_bar = _bar - _foo
  return sorted(in_foo), sorted(in_bar)

def using_sorted(lst1, lst2):
  res1 = list()
  res2 = list()
  n1 = len(lst1)
  n2 = len(lst2)
  i = j = 0
  while True:
    while i < n1 and j < n2 and lst1[i] < lst2[j]: 
      res1.append(lst1[i])
      i += 1
    while j < n2 and i < n1 and lst1[i] > lst2[j]:
      res2.append(lst2[j])
      j += 1
    while i < n1 and j < n2 and lst1[i] == lst2[j]:
      i += 1
      j += 1
    if i == n1:
      res2.extend(lst2[j:])
      break
    elif j == n2:
      res1.extend(lst1[i:])
      break
  return res1, res2
      
assert with_intersection(lst1, lst2) == set_then_sort(lst1, lst2) == using_sorted(lst1, lst2)

# %timeit with_intersection(lst1, lst2) # 306 ms
# %timeit set_then_sort(lst1, lst2)     # 491 ms
# %timeit using_sorted(lst1, lst2)      # 870 ms 

【讨论】:

    【解决方案3】:

    通过在每个列表的末尾放置一个 None 预告片,我们可以使用迭代器 并专注于记录差异。这个算法是O(n+m):

    foo = [1, 3, 4, 5]
    bar = [2, 4, 5, 6]
    
    i_foo = iter(foo + [None])
    i_bar = iter(bar + [None])
    
    n_foo = next(i_foo)
    n_bar = next(i_bar)
    in_foo = []
    in_bar = []
    while True:
        if n_foo is None:
            if n_bar is None:
                break
            in_bar.append(n_bar)
            n_bar = next(i_bar)
            continue
        if n_bar is None:
            in_foo.append(n_foo)
            n_foo = next(i_foo)
        if n_foo == n_bar:
            n_foo = next(i_foo)
            n_bar = next(i_bar)
            continue
        if n_foo < n_bar:
            in_foo.append(n_foo)
            n_foo = next(i_foo)
        else:
            in_bar.append(n_bar)
            n_bar = next(i_bar)
    print(in_foo, in_bar)
    # [1, 3] [2, 6]
    

    【讨论】:

      猜你喜欢
      • 2015-07-19
      • 2012-11-20
      • 2012-12-07
      • 2019-09-24
      • 2023-02-26
      • 2022-10-05
      • 2011-07-09
      相关资源
      最近更新 更多