Python - 从列表的中间开始迭代,然后检查任一侧

Python - iterating beginning with the middle of the list and then checking either side

真的不确定这适合哪里。说,我有一个列表:

>>>a = [1, 2, 3, 4, 5, 6, 7]

我怎样才能以这样的方式迭代它,它会首先检查 4,然后是 5,然后是 3,然后是 6,然后是 2(对于更大的列表以此类推)?我只能计算出中间部分

>>>middle = [len(a)/2 if len(a) % 2 = 0 else ((len(a)+1)/2)]

我真的不确定如何应用它,我也不确定我的中间方法是最好的方法。我想过获取两个索引,并在每次迭代后,从每个相应的索引中加 1 和减 1,但不知道如何使 for 循环遵守这些规则。

关于我为什么需要这个;它用于分析纸牌游戏中的有效玩法,将从给定手牌的中间牌到每一端进行检查,直到可以打出有效牌为止。

首先,here 是一个非常有用的通用实用程序,用于交错两个序列:

def imerge(a, b):
    for i, j in itertools.izip_longest(a,b):
        yield i
        if j is not None:
            yield j

这样,您只需要 imerge

a[len(a) / 2: ]

reversed(a[: len(a) / 2])

您可以继续从列表中间删除:

lst = range(1, 8)
while lst:
    print lst.pop(len(lst)/2)

这不是性能方面的最佳解决方案(从列表中删除项目很昂贵),但它很简单 - 对于一个简单的游戏来说已经足够好了。

编辑:

性能更稳定的解决方案是生成器,它计算元素位置:

def iter_from_middle(lst):
    try:
        middle = len(lst)/2
        yield lst[middle]

        for shift in range(1, middle+1):
            # order is important!
            yield lst[middle - shift]
            yield lst[middle + shift]

    except IndexError: # occures on lst[len(lst)] or for empty list
        raise StopIteration

你也可以玩指数游戏,例如:

>>> a = [1, 2, 3, 4, 5, 6, 7]
>>> [a[(len(a) + (~i, i)[i%2]) // 2] for i in range(len(a))]
[4, 5, 3, 6, 2, 7, 1]

>>> a = [1, 2, 3, 4, 5, 6, 7, 8]
>>> [a[(len(a) + (~i, i)[i%2]) // 2] for i in range(len(a))]
[4, 5, 3, 6, 2, 7, 1, 8]

这是一个生成器,可以为任何给定的长度生成交替索引。它可能是 improved/shorter,但它有效。

def backNforth(length):
    if length == 0:
        return
    else:
        middle = length//2
        yield middle

        for ind in range(1, middle + 1):
            if length > (2 * ind - 1):
                yield middle - ind
            if length > (2 * ind):
                yield middle + ind 

# for testing:
if __name__ == '__main__':
    r = range(9)
    for _ in backNforth(len(r)):
        print(r[_])

使用它,您可以按照您想要的顺序生成项目列表:

a = [1, 2, 3, 4, 5, 6, 7]
a_prime = [a[_] for _ in backNforth(len(a))]

除了中间的元素,我还需要它们的索引。我发现 Wasowski 的回答很有帮助,并对其进行了修改:

def iter_from_middle(lst):
    index = len(lst)//2
    for i in range(len(lst)):
        index = index+i*(-1)**i
        yield index, lst[index]

>>> my_list = [10, 11, 12, 13, 14, 15]
>>> [(index, item) for index, item in iter_from_middle(my_list)]
[(3, 13), (2, 12), (4, 14), (1, 11), (5, 15), (0, 10)]