Python: найдите последовательное изменение в одном члене пар списка, сообщите другое

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

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

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 

Спасибо Тиму

 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) 

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

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

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

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

попробуйте сравнить 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() 
 >>> 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') 

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

 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)) 
 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) 
 >>> 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'] >>> 

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