it-swarm.com.ru

Как сравнить список списков/наборов в Python?

Какой самый простой способ сравнить 2 списка/комплекта и вывести различия? Есть ли встроенные функции, которые помогут мне сравнить вложенные списки/наборы?

Входы:

First_list = [['Test.doc', '1a1a1a', 1111], 
              ['Test2.doc', '2b2b2b', 2222],  
              ['Test3.doc', '3c3c3c', 3333]
             ]  
Secnd_list = [['Test.doc', '1a1a1a', 1111], 
              ['Test2.doc', '2b2b2b', 2222], 
              ['Test3.doc', '8p8p8p', 9999], 
              ['Test4.doc', '4d4d4d', 4444]]  

Ожидаемый результат: 

Differences = [['Test3.doc', '3c3c3c', 3333],
               ['Test3.doc', '8p8p8p', 9999], 
               ['Test4.doc', '4d4d4d', 4444]]
24
tang

Итак, вы хотите разницу между двумя списками предметов.

first_list = [['Test.doc', '1a1a1a', 1111], 
              ['Test2.doc', '2b2b2b', 2222], 
              ['Test3.doc', '3c3c3c', 3333]]
secnd_list = [['Test.doc', '1a1a1a', 1111], 
              ['Test2.doc', '2b2b2b', 2222], 
              ['Test3.doc', '8p8p8p', 9999], 
              ['Test4.doc', '4d4d4d', 4444]]

Сначала я бы превратил каждый список списков в список кортежей, чтобы кортежи можно было хэшировать (списки нет), чтобы вы могли преобразовать свой список кортежей в набор кортежей:

first_Tuple_list = [Tuple(lst) for lst in first_list]
secnd_Tuple_list = [Tuple(lst) for lst in secnd_list]

Тогда вы можете сделать наборы:

first_set = set(first_Tuple_list)
secnd_set = set(secnd_Tuple_list)

РЕДАКТИРОВАТЬ (предложено sdolan): Вы могли бы сделать последние два шага для каждого списка в одну строку:

first_set = set(map(Tuple, first_list))
secnd_set = set(map(Tuple, secnd_list))

Примечание: map - это команда функционального программирования, которая применяет функцию в первом аргументе (в данном случае функцию Tuple) к каждому элементу во втором аргументе (который в нашем случае представляет собой список списков).

и найти симметричную разницу между наборами:

>>> first_set.symmetric_difference(secnd_set) 
set([('Test3.doc', '3c3c3c', 3333),
     ('Test3.doc', '8p8p8p', 9999),
     ('Test4.doc', '4d4d4d', 4444)])

Примечание first_set ^ secnd_set эквивалентно symmetric_difference.

Также, если вы не хотите использовать наборы (например, используя python 2.2), это довольно просто сделать. Например, со списком пониманий:

>>> [x for x in first_list if x not in secnd_list] + [x for x in secnd_list if x not in first_list]
[['Test3.doc', '3c3c3c', 3333],
 ['Test3.doc', '8p8p8p', 9999],
 ['Test4.doc', '4d4d4d', 4444]]

или с функциональной командой filter и функциями lambda. (Вы должны проверить оба пути и совместить).

>>> filter(lambda x: x not in secnd_list, first_list) + filter(lambda x: x not in first_list, secnd_list)

[['Test3.doc', '3c3c3c', 3333],
 ['Test3.doc', '8p8p8p', 9999],
 ['Test4.doc', '4d4d4d', 4444]]
30
dr jimbob

Не уверен, что для этого есть функция Nice, но «ручной» способ сделать это не сложен:

differences = []

for list in firstList:
    if list not in secondList:
        differences.append(list)
3
Sam Magura
>>> First_list = [['Test.doc', '1a1a1a', '1111'], ['Test2.doc', '2b2b2b', '2222'], ['Test3.doc', '3c3c3c', '3333']] 
>>> Secnd_list = [['Test.doc', '1a1a1a', '1111'], ['Test2.doc', '2b2b2b', '2222'], ['Test3.doc', '3c3c3c', '3333'], ['Test4.doc', '4d4d4d', '4444']] 


>>> z = [Tuple(y) for y in First_list]
>>> z
[('Test.doc', '1a1a1a', '1111'), ('Test2.doc', '2b2b2b', '2222'), ('Test3.doc', '3c3c3c', '3333')]
>>> x = [Tuple(y) for y in Secnd_list]
>>> x
[('Test.doc', '1a1a1a', '1111'), ('Test2.doc', '2b2b2b', '2222'), ('Test3.doc', '3c3c3c', '3333'), ('Test4.doc', '4d4d4d', '4444')]


>>> set(x) - set(z)
set([('Test4.doc', '4d4d4d', '4444')])
2
pyfunc

я думаю, вам придется конвертировать ваши списки в наборы:

>>> a = {('a', 'b'), ('c', 'd'), ('e', 'f')}
>>> b = {('a', 'b'), ('h', 'g')}
>>> a.symmetric_difference(b)
{('e', 'f'), ('h', 'g'), ('c', 'd')}
1
user126284

Используя набор пониманий, вы можете сделать его однострочным. Если ты хочешь:

чтобы получить набор кортежей, тогда:

Differences = {Tuple(i) for i in First_list} ^ {Tuple(i) for i in Secnd_list}

Или, чтобы получить список кортежей, тогда:

Differences = list({Tuple(i) for i in First_list} ^ {Tuple(i) for i in Secnd_list})

Или, чтобы получить список списков (если вы действительно хотите), то:

Differences = [list(j) for j in {Tuple(i) for i in First_list} ^ {Tuple(i) for i in Secnd_list}]

PS: Я читал здесь: https://stackoverflow.com/a/10973817/4900095 что функция map () не является Pythonic способ делать вещи.

0
Sukrit Gupta

Старый вопрос, но вот решение, которое я использую для возврата уникальных элементов, не найденных в обоих списках.

Я использую это для сравнения значений, возвращаемых из базы данных, и значений, сгенерированных пакетом искателя каталогов. Мне не понравились другие решения, которые я нашел, потому что многие из них не могли динамически обрабатывать как плоские, так и вложенные списки.

def differentiate(x, y):
    """
    Retrieve a unique of list of elements that do not exist in both x and y.
    Capable of parsing one-dimensional (flat) and two-dimensional (lists of lists) lists.

    :param x: list #1
    :param y: list #2
    :return: list of unique values
    """
    # Validate both lists, confirm either are empty
    if len(x) == 0 and len(y) > 0:
        return y  # All y values are unique if x is empty
    Elif len(y) == 0 and len(x) > 0:
        return x  # All x values are unique if y is empty

    # Get the input type to convert back to before return
    try:
        input_type = type(x[0])
    except IndexError:
        input_type = type(y[0])

    # Dealing with a 2D dataset (list of lists)
    try:
        # Immutable and Unique - Convert list of tuples into set of tuples
        first_set = set(map(Tuple, x))
        secnd_set = set(map(Tuple, y))

    # Dealing with a 1D dataset (list of items)
    except TypeError:
        # Unique values only
        first_set = set(x)
        secnd_set = set(y)

    # Determine which list is longest
    longest = first_set if len(first_set) > len(secnd_set) else secnd_set
    shortest = secnd_set if len(first_set) > len(secnd_set) else first_set

    # Generate set of non-shared values and return list of values in original type
    return [input_type(i) for i in {i for i in longest if i not in shortest}]
0
Stephen Neal

http://docs.python.org/library/difflib.html является хорошей отправной точкой для того, что вы ищете.

Если вы примените его рекурсивно к дельтам, вы сможете обрабатывать вложенные структуры данных. Но это займет некоторую работу.

0
btilly