【问题标题】:Comparing Order of 2 Python Lists比较 2 个 Python 列表的顺序
【发布时间】:2016-05-05 23:20:39
【问题描述】:

我正在寻找比较 2 个 Python 列表 list1list2 的顺序的帮助,以检测 list2 何时出现故障.

  • list1 是静态的,包含字符串 a,b,c,d,e,f,g,h,i,j。这是“正确”的顺序。
  • list2 包含相同的字符串,但字符串的顺序和数量可能会发生变化。 (例如a,b,f,d,e,g,c,h,i,ja,b,c,d,e

我正在寻找一种有效的方法,通过将 list2list1 进行比较来检测何时是我们的订单。

例如,如果 list2a,c,d,e,g,i 应该返回 true(因为字符串是按顺序排列的)

同时,如果 list2a,d,b,c,e 应该返回 false(因为字符串 d 出现乱序)

【问题讨论】:

  • 由于list1 总是按字母顺序排列,我想知道您是否需要检查list2。如果您简单地检查list2 是否按字母顺序排列,它会起作用吗?

标签: python string list


【解决方案1】:

首先,让我们定义list1

>>> list1='a,b,c,d,e,f,g,h,i,j'.split(',')
>>> list1
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']

虽然您的list1 恰好按字母顺序排列,但我们不会假设。这段代码无论如何都有效。

现在,让我们创建一个无序的list2

>>> list2 = 'a,b,f,d,e,g,c,h,i,j'.split(',')
>>> list2
['a', 'b', 'f', 'd', 'e', 'g', 'c', 'h', 'i', 'j']

这里是如何测试list2是否有问题:

>>> list2 == sorted(list2, key=lambda c: list1.index(c))
False

False 表示乱序。

这是一个按顺序排列的示例:

>>> list2 = 'a,b,d,e'.split(',')
>>> list2 == sorted(list2, key=lambda c: list1.index(c))
True

True 表示有序。

忽略 list1 中不在 list2 中的元素

让我们考虑一个list2,它有一个不在list1 中的元素:

>>> list2 = 'a,b,d,d,e,z'.split(',')

要忽略不需要的元素,让我们创建list2b

>>> list2b = [c for c in list2 if c in list1]

然后我们可以像以前一样测试:

>>> list2b == sorted(list2b, key=lambda c: list1.index(c))
True

替代方案不使用sorted

>>> list2b = ['a', 'b', 'd', 'd', 'e']
>>> indices = [list1.index(c) for c in list2b]
>>> all(c <= indices[i+1] for i, c in enumerate(indices[:-1]))
True

【讨论】:

  • 这很完美!谢谢你。还有一个问题:如果 list2 包含一个不在 list1 中的字符串,我该如何忽略它?
  • @chasm 很高兴它成功了。只需要多行代码来处理不需要的字符串。查看更新的答案。
  • 所有这些index 调用可能会变得非常昂贵(二次时间!),并且排序是判断输入是否已经排序的低效方法。
【解决方案2】:

您为什么需要将它与list1 进行比较,因为list1 似乎是按字母顺序排列的?您不能执行以下操作吗?

def is_sorted(alist):
    return alist == sorted(alist)

print is_sorted(['a','c','d','e','g','i'])
# True

print is_sorted(['a','d','b','c','e'])
# False

【讨论】:

  • 这可行,但是,list2 是动态的并且经常更改。
  • 假设list1 始终与您的问题中概述的相同,那么我认为这是最简单的答案。您真正需要做的只是检查list2 本身是否按字母顺序排列,此函数将始终检查您传递给它的任何字母字符列表。
  • 我们不能假设 list1 中的项目在一般情况下是按字典顺序排列的。如果我们可以,那么就没有问题了。如果 list2 非常大,那么基于 sorted() 的解决方案,普通的 issorted 可能在时间上是线性的并提前终止:issorted = lambda L: all(x &lt; y for x,y in pairwise(L))
【解决方案3】:

这是一个在预期线性时间内运行的解决方案。如果 list1 始终是 10 个元素,而 list2 不再是,这并不是很重要,但是如果列表更长,基于 index 的解决方案将经历极度减速。

首先,我们预处理list1,以便我们可以快速找到任何元素的索引。 (如果我们有多个list2s,我们可以这样做一次,然后使用预处理后的输出快速判断多个list2s是否排序):

list1_indices = {item: i for i, item in enumerate(list1)}

然后,我们检查list2 的每个元素在list1 中的索引是否低于list2 的下一个元素:

is_sorted = all(list1_indices[x] < list1_indices[y] for x, y in zip(list2, list2[1:]))

我们可以使用itertools.izipitertools.islice 做得更好,以避免实现整个zip 列表,如果我们在列表的早期检测到list2 出现故障,我们可以节省大量工作:

# On Python 3, we can just use zip. islice is still needed, though.
from itertools import izip, islice
is_sorted = all(list1_indices[x] < list1_indices[y]
                for x, y in izip(list2, islice(list2, 1, None)))

【讨论】:

  • 您是否尝试过衡量 list2 应该有多大才能使 itertools 解决方案变得更快? is_sorted = lambda L: L == sorted(L, key=rank.__getitem__)rank = list1_indices 相同,这对于小型列表可能已经足够了。
【解决方案4】:
is_sorted = not any(list1.index(list2[i]) > list1.index(list2[i+1]) for i in range(len(list2)-1))

函数any 如果迭代中的任何项为真,则返回真。我将它与一个生成器表达式结合起来,该表达式循环遍历 list2 的所有值,并确保它们按照 list1 的顺序排列。

【讨论】:

    【解决方案5】:
    if list2 == sorted(list2,key=lambda element:list1.index(element)):
        print('sorted')
    

    【讨论】:

    • 你的第一个版本有缺陷
    【解决方案6】:

    假设当您编写 list1 是字符串 a,b,c,d,e,f,g,h,i 时,这意味着 a 可能是 'zebra' 而字符串 b 实际上可能是 'elephant'所以顺序可能不是按字母顺序排列的。此外,如果项目在 list2 中但不在 list1 中,则此方法将返回 false。

    good_list2 = ['a','c','d','e','g','i']
    
    bad_list2 = ['a','d','b','c','e']
    
    def verify(somelist):
        list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
        while len(list1) > 0:
            try:
                list1 = list1[:list1.index(somelist.pop())]
            except ValueError:
                return False
        return True
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-21
      • 1970-01-01
      • 2015-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-18
      • 1970-01-01
      相关资源
      最近更新 更多