Поиск нестандартных элементов в списках

Я пытаюсь написать фрагмент кода, который может автоматически учитывать выражение. Например, если у меня есть два списка [1,2,3,4] и [2,3,5], код должен найти общие элементы в двух списках [2,3] и объединить остальные элементы вместе в новом списке, будучи [1,4,5].

Из этого сообщения: Как найти пересечение списка? Я вижу, что общие элементы можно найти по

set([1,2,3,4]&set([2,3,5]). 

Есть ли простой способ получить необычные элементы из каждого списка, в моем примере это [1,4] и [5]?

Я могу пойти дальше и сделать цикл for:

lists = [[1,2,3,4],[2,3,5]]
conCommon = []
common = [2,3]
for elem in lists:
    for elem in eachList:
    if elem not in common:
        nonCommon += elem

Но это кажется излишним и неэффективным. Предоставляет ли Python какую-либо удобную функцию, которая может это сделать? Заранее спасибо!!


person turtlesoup    schedule 05.07.2012    source источник
comment
вы хотите получить отдельные списки, такие как [1,4] и [5], или один [1,4,5]?   -  person nye17    schedule 05.07.2012


Ответы (7)


Используйте оператор симметричной разности для sets (он же оператор XOR):

>>> set([1,2,3]) ^ set([3,4,5])
set([1, 2, 4, 5])
person Amber    schedule 05.07.2012
comment
о вау спасибо!! Но занимает ли приведенный выше код столько же времени вычислений и памяти, сколько set([1,2,3])&set([3,4,5])? Или это не оказывает существенного влияния на производительность кода? - person turtlesoup; 05.07.2012
comment
Это самый эффективный способ достичь своей цели. Его сложность того же порядка, что и & (а именно, линейна по количеству элементов в наборах). - person Amber; 05.07.2012

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

b1 = [1,2,3,4,5,9,11,15]
b2 = [4,5,6,7,8]
set(b1).intersection(b2)
Out[22]: {4, 5}

Лучшее в использовании этого кода то, что он работает довольно быстро и для больших данных. У меня есть b1 с 607139 и b2 с 296029 элементами, когда я использую эту логику, я получаю результаты за 2,9 секунды.

person saimadhu.polamuri    schedule 18.08.2015
comment
Это не отвечает на исходный вопрос. Просьба наоборот. - person Gina Marano; 09.06.2020

Старый вопрос, но похоже, что у python есть встроенная функция, обеспечивающая именно то, что вы ищете: .difference().

ПРИМЕР

list_one = [1,2,3,4]
list_two = [2,3,5]

one_not_two = set(list_one).difference(list_two)
# set([1, 4])

two_not_one = set(list_two).difference(list_one)
# set([5])

Это также может быть записано как:

one_not_two = set(list_one) - set(list_two)

Время

Я провел некоторые временные тесты на обоих, и оказалось, что .difference() имеет небольшое преимущество, в пределах 10-15%, но каждому методу потребовалось около одной восьмой секунды для фильтрации 1M элементов (случайные целые числа от 500 до 100 000), поэтому, если только вы очень чувствительны ко времени, возможно, оно несущественно.

Другие примечания

Похоже, что ОП ищет решение, которое предоставляет два отдельных списка (или набора) - один, в котором первый содержит элементы, которых нет во втором, и наоборот. Большинство предыдущих ответов возвращают один список или набор, включающий все элементы.

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

Если OP хочет поддерживать дубликаты, можно использовать понимание списка, например:

one_not_two = [ x for x in list_one if x not in list_two ]
two_not_one = [ x for x in list_two if x not in list_one ]

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

person elPastor    schedule 21.01.2019

Вы можете использовать метод атрибута .__xor__.

set([1,2,3,4]).__xor__(set([2,3,5]))

or

a = set([1,2,3,4])
b = set([2,3,5])
a.__xor__(b)
person SuperNova    schedule 01.06.2017

Это должно получить общие и оставшиеся элементы

lis1=[1,2,3,4,5,6,2,3,1]
lis2=[4,5,8,7,10,6,9,8]

common = list(dict.fromkeys([l1 for l1 in lis1 if l1 in lis2]))
remaining = list(filter(lambda i: i not in common, lis1+lis2))

common = [4, 5, 6]

remaining = [1, 2, 3, 2, 3, 1, 8, 7, 10, 9, 8]

person Shahir Ansari    schedule 05.03.2020

Вы можете использовать команду symmetric_difference

x = {1,2,3} y = {2,3,4}

г = set.difference (х, у)

Выход будет: z = {1,4}

person Gaurav Arora    schedule 10.05.2020

Все хорошие решения, начиная от базового стиля DSA и заканчивая использованием встроенных функций:

# Time: O(2n)
def solution1(arr1, arr2):
  map = {}
  maxLength = max(len(arr1), len(arr2))
  for i in range(maxLength):
    if(arr1[i]):
      if(not map.get(arr1[i])):
        map[arr1[i]] = [True, False]
      else:
        map[arr1[i]][0] = True
    if(arr2[i]):
      if(not map.get(arr2[i])):
        map[arr2[i]] = [False, True]
      else:
        map[arr2[i]][1] = False

  res = [];
  for key, value in map.items():
    if(value[0] == False or value[1] == False):
      res.append(key)

  return res

def solution2(arr1, arr2):
  return set(arr1) ^ set(arr2)

def solution3(arr1, arr2):
  return (set(arr1).difference(arr2), set(arr2).difference(arr1))

def solution4(arr1, arr2):
  return set(arr1).__xor__(set(arr2))

print(solution1([1,2,3], [2,4,6]))
print(solution2([1,2,3], [2,4,6]))
print(solution3([1,2,3], [2,4,6]))
print(solution4([1,2,3], [2,4,6]))
person Vinit Khandelwal    schedule 05.07.2021