Python: как объединить два списка списков вместе, избегая повторений?

#python #list

#python #Список

Вопрос:

У меня есть два списка списков:

ll1=[[17],[35,6],[47,58,86]]

ll2=[[19],[75,8],[17,58,86]]

Как я мог бы объединить их, возможно, в for цикле, создав новый список списков ll3 и пропустив повторяющиеся значения?

Предполагаемый результат был бы: ll3=[[17,19],[35,6,75,8],[47,58,86]]

Что равносильно объединению двух списков списков вместе, а затем удалению повторяющихся значений.

Комментарии:

1. вы пытаетесь избежать ЛЮБОГО значения, которое было в любом из предыдущих списков во время слияния?

2. всегда ли списки имеют одинаковый размер??

3. избавление от повторяющихся значений обычно означает, что вы все еще сохраняете одно из значений, вы действительно имеете в виду, что в третьем примере не должно быть 58 и 86?

4. Это не имеет смысла, потому что вы избавляетесь от 58, но сохраняете 17.

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

Ответ №1:

Предыдущие ответы, похоже, не соответствуют вашему требованию о том, что списки могут быть разных размеров.

В моем решении используются set пересечения и объединения. Примечание. Я использую Python2, измените zip_longest на izip_longest .

 ll1=[[17],[35,6],[47,58,86]]
ll2=[[19],[75,8],[17,58,86]]

from itertools import zip_longest

ll3 = []
seen = set()
for a, b in zip_longest(ll1, ll2, fillvalue=[]):
    new = (set(a) | set(b)) - seen
    ll3.append(list(new))
    seen |= new
print (ll3)
  

Это выведет:

 [[17, 19], [8, 75, 35, 6], [58, 86, 47]]
  

Это также сработает, если:

 ll1=[[17],[35,6],[47,58,86],[5]]
ll2=[[19],[75,8],[17,58,86]]
  

возврат:

 [[17, 19], [8, 75, 35, 6], [58, 86, 47], [5]]
  

Комментарии:

1. Почему я получаю ImportError: cannot import name zip_longest ? Никогда раньше мне это не приходило в голову. Используя Python 2.7.11, 32-разрядный

2. @CF84 если вы используете Python2, измените имя на izip_longest при импорте и в for цикле

3. Извините, я допустил небольшую ошибку. Предполагаемый результат должен включать 58 и 86 , которые я ошибочно пропустил. Проверьте мою правку и, опять же, приношу извинения.

4. @CF84 Я просто немного почистил операции с разделением по битам: теперь это еще короче.

5. @CF84 хорошо, к счастью, это легко исправить: просто измените ^ на | (я отредактировал соответствующим образом)

Ответ №2:

 seen = set()
res = []
for a, b in zip(l1, l2):
    subres = []
    for item in a:
        seen.add(item)
        if item not in b and item not in seen:
            subres.append(item)
    for item in b:
        seen.add(item)
        if item not in a and item not in seen:
            subres.append(item)
    res.append(subres)
  

Комментарии:

1. ха, практически одно и то же решение примерно в одно и то же время

2. Рассмотрите возможность использования set.symmetric_difference

3. @PM2Ring Я хотел избежать использования set s для a и b в случае, если порядок имеет значение.

4. Исходя из предыдущего вопроса OP, я почти уверен, что порядок в подсписке не имеет значения. Но неплохо бы получить разъяснения по подобным вопросам в комментариях к вопросу.

Ответ №3:

Для того, что, как вам кажется, вы ищете, я бы сохранил набор предыдущих значений.

 old_values =  {}
ll3 = []
for list_a, list_b in zip(ll1,ll2):
  temp_list = []
  for item in list_a:
    if item in old_values or item in list_b:
      pass
    else:
      temp_list.append(item)
      old_values.add(item)
  for item in list_b:
    if item in old_values or item in list_a:
      pass
    else:
      temp_list.append(item)
      old_values.add(item)
  ll3.append(temp_list)
  

Комментарии:

1. и вы могли бы изменить мои условия, чтобы они соответствовали ответу @PatrickHaugh. Его немного чище.

Ответ №4:

В общем случае — предполагая, что порядок элементов в результирующих вложенных списках не важен и 2 списка имеют одинаковую длину, вы можете использовать zip и set

 ll3 = [set(l1   l2) - set(l1).intersection(l2) for l1, l2 in zip(ll1, ll2)]
seen = set()
for idx, elem in enumerate(ll3):
    ll3[idx] = list(elem - seen)
    seen.update(elem)
  

Комментарии:

1. Это не пропускает повторяющееся значение, но вместо этого включает одну копию в результат

2. @volcano это не сразу видно из вопроса, но OP также хочет исключить предыдущие увиденные значения (в данном случае вторые 17).

3. @brianpck, спасибо за разъяснение, исправлено, что