Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Really not sure where this fits. Say, I have a list:

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

How can I iterate it in such a way, that it will check 4 first, then 5, then 3, then 6, and then 2(and so on for bigger lists)? I have only been able to work out the middle which is

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

I'm really not sure how to apply this, nor am I sure that my way of working out the middle is the best way. I've thought of grabbing two indexes and after each iteration, adding 1 and subtracting 1 from each respective index but have no idea how to make a for loop abide by these rules.

With regards as to why I need this; it's for analysing a valid play in a card game and will check from the middle card of a given hand up to each end until a valid card can be played.

like image 401
Laefica Avatar asked May 22 '15 12:05

Laefica


3 Answers

You can just keep removing from the middle of list:

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

This is not the best solution performance-wise (removing item from list is expensive), but it is simple - good enough for a simple game.

EDIT:

More performance stable solution would be a generator, that calculates element position:

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
like image 99
m.wasowski Avatar answered Sep 29 '22 10:09

m.wasowski


To begin with, here is a very useful general purpose utility to interleave two sequences:

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

with that, you just need to imerge

a[len(a) / 2: ]

with

reversed(a[: len(a) / 2])
like image 28
Ami Tavory Avatar answered Sep 29 '22 09:09

Ami Tavory


You could also play index games, for example:

>>> 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]
like image 42
Stefan Pochmann Avatar answered Sep 29 '22 10:09

Stefan Pochmann