Python - сравнивать вложенные списки и добавлять совпадения в новый список? - PullRequest
5 голосов
/ 29 марта 2010

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

x = [['1', 'a', 'b'], ['2', 'c', 'd']]

y = [['1', 'z', 'x'], ['4', 'z', 'x']]

match = []

def find_match():
    for i in x:
        for j in y:
            if i[0] == j[0]:
                 match.append(j)
            return match

Возвращает:

[['1', 'x'], ['1', 'y'], ['1', 'x'], ['1', 'y'], ['1', 'z', 'x']]

Будет ли хорошей практикой повторная обработка списка для удаления дубликатов или это можно сделать более простым способом?

Кроме того, лучше ли для сравнения использовать кортежи и / или кортежи кортежей?

Любая помощь очень ценится.

С уважением, Seafoid.

Ответы [ 5 ]

6 голосов
/ 30 марта 2010
  • Используйте наборы для получения коллекций без дубликатов.

    • Вы должны будете использовать кортежи вместо списков в качестве элементов, потому что установленные элементы должны быть хэшируемыми.
  • Код, который вы разместили, похоже, не генерирует вывод, который вы опубликовали. Я понятия не имею, как вы должны генерировать этот вывод из этого ввода. Например, у выхода есть 'y', а у входа нет.

  • Я думаю, что дизайн вашей функции может быть значительно улучшен. В настоящее время вы определяете x, y и match как уровень модуля и явно читаете и изменяете их. Это не то, как вы хотите проектировать функции - как правило, функция не должна что-то мутировать на глобальном уровне. Нужно явно передать все, что нужно, и вернуть результат, а не получить информацию и изменить что-либо вне ее.

    я бы поменял

    x = some list
    y = some list
    match = []
    def find_match():
        for i in x:
            for j in y:
                if i[0] == j[0]:
                     match.append(j)
        return match # This is the only line I changed. I think you meant 
                     # your return to be over here?
    find_match()
    

    до

    x = some list
    y = some list
    
    def find_match(x, y):
        match = []
        for i in x:
            for j in y:
                if i[0] == j[0]:
                     match.append(j)
         return match
    match = find_match(x, y)
    
  • Чтобы перенести это последнее изменение на следующий уровень, я обычно заменяю паттерн

    def f(...):
        return_value = []
        for...
            return_value.append(foo)
        return return_value
    

    с аналогичным генератором

    def f(...):
        for...
            yield foo
    

    , что сделало бы вышеуказанную функцию

    def find_match(x, y):
        for i in x:
            for j in y:
                if i[0] == j[0]:
                     yield j
    

    другой способ выразить эффект этого генератора - выражение генератора (j for i in x for j in y if i[0] == j[0]).

2 голосов
/ 29 марта 2010

Вы можете сделать это намного проще, используя наборы.

set_x = set([i[0] for i in x])
set_y = set([i[0] for i in y])
matches = list(set_x & set_y)
2 голосов
/ 29 марта 2010

Я не знаю, правильно ли я понимаю ваш вопрос, но, учитывая ваш пример, кажется, что вы, возможно, используете неправильный индекс:

изменение

if i[1] == j[1]:

в

if i[0] == j[0]:
1 голос
/ 29 марта 2010
if i[1] == j[1]

проверяет, являются ли элементы second массивов идентичными. Вы хотите if i[0] == j[0].

В противном случае я нахожу ваш код вполне читабельным и не обязательно буду его менять.

0 голосов
/ 29 марта 2010

Здесь также должно работать более простое выражение:

list_of_lists = filter(lambda l: l[0][0] == l[1][0], zip(x, y))
map(lambda l: l[1], list_of_lists)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...