Python: найти последовательные изменения в одном элементе списка пар, сообщить о другом - PullRequest
1 голос
/ 30 августа 2010

Должен быть более простой, более питонский способ сделать это.

Учитывая этот список пар:

pp = [('a',1),('b',1),('c',1),('d',2),('e',2)]

Как мне легче всего найти первый предмет в соседних парах, где меняется второй предмет (здесь, с 1 по 2) Таким образом я ищу ['c', 'd']. Предположим, что для всего списка будет только одно изменение в паре [1], но это может быть строка.

Этот код работает, но кажется мучительно длинным и громоздким.

for i, pair in enumerate(pp):
    if i == 0: 
        pInitial = pair[0] 
        sgInitial = pair[1]
    pNext = pair[0]
    sgNext = pair[1]
    if sgInitial == sgNext:
        sgInitial = sgNext
        pInitial = pNext
    else:
        pOne = pInitial
        pTwo = pNext
        x = [pOne, pTwo]
        print x
        break

Спасибо Тим

Ответы [ 7 ]

2 голосов
/ 30 августа 2010
import itertools as it

pp = [('a',1),('b',1),('c',1),('d',2),('e',2)]

# with normal zip and slicing
for a,b in zip(pp,pp[1:]):
    if a[1] != b[1]:
        x=(a[0],b[0])
        print x
        break
# with generators and izip
iterfirst = (b for a,b in pp)
itersecond = (b for a,b in pp[1:])
iterfirstsymbol = (a for a,b in pp)
itersecondsymbol = (a for a,b in pp[1:])
iteranswer = it.izip(iterfirstsymbol, itersecondsymbol, iterfirst, itersecond)

print next((symbol1, symbol2)
           for symbol1,symbol2, first, second in iteranswer
           if first != second)

Добавлена ​​моя читабельная версия генератора.

0 голосов
/ 12 октября 2011
>>> pp = [('a',1),('b',1),('c',1),('d',2),('e',2)]
>>> [[t1, t2] for ((t1, v1), (t2, v2)) in zip(pp, pp[1:]) if v1 != v2] [0]
['c', 'd']
>>>

Мне нравится это для ясности ... если вы находите ясное понимание списка. Он создает два временных списка: pp [1:] и результат zip (). Затем он сравнивает все соседние пары и дает вам первое найденное изменение.

Это похожее выражение генератора не создает временные списки и останавливает обработку, когда оно достигает первого изменения:

>>> from itertools import islice, izip
>>> ([t1, t2] for ((t1, v1), (t2, v2)) in izip(pp, islice(pp, 1, None)) 
...           if v1 != v2
... ).next()
['c', 'd']
>>>

Все примеры на этой странице более компактны, чем если бы вы хотели отлавливать ошибки.

0 голосов
/ 30 августа 2010
pp = [('a',1),('b',1),('c',1),('d',2),('e',2)]
def find_first(pp):
    for i,(a,b) in enumerate(pp):
        if i == 0: oldb = b
        else:
            if b != oldb: return i
    return None
print find_first(pp)
0 голосов
/ 30 августа 2010

Вот что-то (простое?) С рекурсией:

def first_diff( seq, key=lambda x:x ):
    """ returns the first items a,b of `seq` with `key(a) != key(b)` """
    it = iter(seq)
    def test(last): # recursive function
        cur = next(it)
        if key(last) != key(cur):
            return last, cur
        else:
            return test(cur)
    return test(next(it))

print first_diff( pp, key=lambda x:x[1]) # (('c', 1), ('d', 2))
0 голосов
/ 30 августа 2010
>>> import itertools
>>> pp = [('a',1),('b',1),('c',1),('d',2),('e',2)]
>>> gb = itertools.groupby(pp, key=lambda x: x[1])
>>> f = lambda x: list(next(gb)[1])[x][0]
>>> f(-1), f(0)
('c', 'd')
0 голосов
/ 30 августа 2010

попробуйте сравнить pp[:-1] с pp[1:], что-то вроде

[a for a in zip(pp[:-1], pp[1:]) if a[0][1] != a[1][1]]

(сначала посмотрите на zip(pp[:-1], pp[1:]), чтобы увидеть, что происходит

редактирование:

Полагаю, тебе понадобится

([a[0][0], a[1][0]] for a in zip(pp[:-1], pp[1:]) if a[0][1] != a[1][1]).next()
0 голосов
/ 30 августа 2010

Вы можете попробовать что-то вроде:

[[pp[i][0],pp[i+1][0]] for i in xrange(len(pp)-1) if pp[i][1]!=pp[i+1][1]][0]

(используя понимание списка)

...