2013-04-05 7 views
4

Учитывая два списка одинаковой длины, как можно эффективно найти первую позицию, где соответствующие элементы этих списков не равны? В принципе мне нужен либо индекс, либо два неравных элемента.Python: найти первое несоответствие в двух списках

Мне интересно, существует ли лаконичное «питоновское» решение без явной итерации по спискам.

+1

Итак - вы господствующий о ut 'enumerate (zip (a, b))' then? –

+0

Мне очень интересно, что вы подразумеваете под «лаконичным питоническим решением». Какой speask против этого скучно: сортировать, уменьшать (дубликаты), сравнивать - подходить? или даже перечисление? – Najzero

+0

@Najzero: что-то с lambdas или с помощью некоторых функций, о которых я не знаю, что позволит решить проблему в одной строке.Точнее, я хочу как можно меньше кода :) –

ответ

3

Вы не можете избежать итерации по спискам, но вы можете сделать это с пониманием и получить элегантное решение:

next((idx, x, y) for idx, (x, y) in enumerate(zip(list1, list2)) if x!=y) 

Если вы хотите что-то менее одна линия Centric вы можете разделить его, как это

coupled_idx = enumerate(zip(list1, list2)) 
res = next(idx for idx, (x, y) in coupled_idx if x!=y) 

EDIT:

как дополнение, если вам нужно проверить случай, когда два списка может быть укомплектовать равен, вы можете добавить второй параметр к следующей функции, сообщает, что возвращается, если индекс не найден. Наиболее распространенным вариантом является не возвращать None:

coupled_idx = enumerate(zip(list1, list2)) 
res = next((idx for idx, (x, y) in coupled_idx if x!=y), None) 

Обратите внимание, что вам нужно заключить выражение генератора между круглыми скобками, потому что это не единственный аргумент функции в этом вызове.

Просто добавьте немного удовольствия, вы также можете спросить n-ю другую пару, связав выражения. Например, это дает вам все пары до пятого одного (заполнение None, если пара отсутствует)

coupled_idx = enumerate(zip(list1, list2)) 
coupler = (idx for idx, (x, y) in coupled_idx if x!=y) 
res = [ next(coupler, None) for _ in range(5) ] 

EDIT2:

Такое решение на самом деле создать копию как списка с помощью почтового индекса функция. Если вам нужно избежать этого, вы можете использовать функцию izip вместо модуля itertools.

И о забавной части, вы можете выбрать только certains решения через Ислицу функции fromt он же модуль

+0

Это был быстрый ответ, к сожалению, он ломается, если оба списка равны. – georg

+0

Я редактировал для этого: – EnricoGiampieri

+0

res = [(idx, x, y) для idx, (x, y) в enumerate (zip (list1, list2)), если x! = Y] создает список (idx, x, y), где есть различия и пустой список, когда списки равны. – StuGrey

0
In [1]: l1=[1,2,3] 

In [2]: l2=[1,4,5] 

In [4]: next(i for i, (el1, el2) in enumerate(zip(l1, l2)) if el1 != el2) 
Out[4]: 1 

Здесь 1 является первым индексом, где l1 и l2 отличаются.

0

Попробуйте это:

next(i for i, (el1,el2) in enumerate(zip(li1,li2)) if el1 != el2) 

Или это эквивалентно функции:

def first_diff(li1, li2): 
    for i, (el1,el2) in enumerate(zip(li1,li2)): 
     if el1 != el2: 
      return i 
    return False 

Пример

>>> li1 = range(32) 
>>> li2 = range(32) 
>>> li2[10] = 2 
>>> next(i for i, (el1,el2) in enumerate(zip(li1,li2)) if el1 != el2) 
10 
>>> first_diff(li1, li2) 
10 
+0

Я думаю, что этот вопрос является ярким примером принципа «должен быть один способ только сделать что-то». до сих пор все отвечали на один и тот же ответ с разными именами переменных :) – EnricoGiampieri

2
>>> from operator import eq 
>>> a = [1, 2, 4, 3] 
>>> b = [1, 2, 3, 4] 
>>> map(eq, a, b).index(False) 
2 
+0

+1. Это интересная вариация проблемы. Это немного хрупкое против равных списков, поскольку это вызовет исключение. – EnricoGiampieri

+0

@ EnricoGiampieri OP не сказал, как справиться с несоответствиями. Я думаю, что исключение на самом деле довольно ясно, поэтому его можно просто проверить. Фактическая проблема заключается в том, что это будет неэффективно для огромных списков. – jamylak

0
>>> from itertools import dropwhile 
>>> a = [1, 2, 4, 3] 
>>> b = [1, 2, 3, 4] 
>>> next(dropwhile(lambda x: x[0] == x[1], zip(a, b))) 
(4, 3) 
Смежные вопросы