Pythonic方法确定两个给定的数字是否在整数序列中相邻

时间:2017-04-28 22:15:47

标签: python algorithm

给定整数a,b使得a< b;和一些有序的可迭代整数序列seq。确定ab是否按顺序出现在seq

中的任何位置

明显的第一步是:

假设 a< b(如果a> b,只需切换值)。

>>> idx = 0
>>> for i in range(0, len(l)):
...     if a == l[i]:
...             idx = i
... 
>>> b == l[idx+1]

这感觉很笨拙。

例如,给定

>>> [1, 2, 3, 8]

如果a为1且b为3,则它们不相邻,如果b中的3为8,则为。

有些东西告诉我有更多的pythonic方法可以做到这一点,或者这是一个很好探索的问题,我错过了更清晰/更清晰的方法来接近它。

6 个答案:

答案 0 :(得分:3)

使用任意缩减器来确定是否有任何相邻的对匹配(a,b):

>>> seq = [1, 2, 3, 8]
>>> a = 3
>>> b = 8
>>> any((seq[i], seq[i+1]) == (a,b) for i in range(len(seq)-1))
True
>>> b = 1
>>> any((seq[i], seq[i+1]) == (a,b) for i in range(len(seq)-1))
False
>>> 

答案 1 :(得分:3)

使用 zip 的简短回答:

(a, b) in zip(seq[:-1], seq[1:])

当你被允许翻转

时,这是有效的
(a, b) in zip(seq[:-1], seq[1:]) or (b, a) in zip(seq[:-1], seq[1:])

要使其逻辑正确,您可以先测试a in seq。如果它通过,则应保持先前的测试。

有关zip正在做什么的一些信息

>>> print seq 
[1, 2, 3, 8]
>>> zip(seq[:-1], seq[1:])
[(1, 2), (2, 3), (3, 8)]

使用itertools包中的 izip islice

from itertools import izip, islice
N = len(seq)
(a, b) in izip(islice(seq, 0, N - 1), islice(seq, 1, N))

答案 2 :(得分:2)

您可以遍历序列中的元素对,并检查一对是否包含ab。使用itertools中的pairwise食谱:

>>> from itertools import tee
>>> def pairwise(iterable):
...     x, y = tee(iterable)
...     next(y, None)
...     return zip(x, y)
... 
>>> a, b, seq = 3, 8, [1, 2, 3, 8]
>>> (a, b) in pairwise(seq)
True

这对任意大型序列都很快(与列表切片解决方案不同)。

答案 3 :(得分:2)

使用binary search将是最快的。

以下实施应该相当快,即使{​​{1}}也适用于未排序的列表,并且列表中不存在b > a和/或a(将返回{{ 1}}在这种情况下):

b

答案 4 :(得分:1)

其他人正在实施与问题定义要实现的完全不同的东西。具体来说,我们应该做以下事情:

  

确定b == l[i+1]是否暗示i < len(l) {/ 1}} a

即使在列表中也不需要ba,并且(如果“有序”不是指“已排序”)b和{{ 1}}可以在列表中多次显示。

要确定问题定义实际上要确定的内容,我们可以遍历所有相邻元素对并测试暗示是否成立:

if l and l[-1] == a:
    # Problem definition doesn't say what to do.
    shrug()
return all(x != a or y == b for (x, y) in zip(l[:-1], l[1:]))

如果我们 假设输入已排序,我们可以通过二分搜索做得更好:

import bisect

if l and l[-1] == a:
    # We still don't know what to do for this case.
    shrug()

possible_leftmost_a_index = bisect.bisect_left(l, a)
if possible_leftmost_a_index == len(a):
    # All elements of l are lower than a.
    return True
elif l[possible_leftmost_a_index] != a:
    # a isn't in the list.
    return True
elif l[possible_leftmost_a_index+1] == b:
    # The implication holds. (We don't have to look for more occurrences of a,
    # because bisect guarantees no a occurrences to the left, and everything to
    # the right is greater than a.)
    return True
else:
    return False

答案 5 :(得分:1)

问题可分为两个子问题:

  1. 将序列转换为成对序列,例如[a, b, c]应转换为[(a, b), (b, c)]
  2. 确定给定的对(x, y)是否在步骤1中生成的序列中。
  3. 您可以使用以下符号将iterable转换为一系列对:

    def pairs(collection):
        collection = iter(collection)
        a = next(collection)
        for b in collection:
            yield a, b
            a = b
    

    collection可以是列表,也可以是无限生成器。

    要确定(x, y)是否在pairs的输出中,您只需执行以下操作:

    (x, y) in pairs(seq)
    
相关问题