Python: симметричная разница между списком наборов строк

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

Например, у меня есть следующий список:

targets = [{'B', 'C', 'A'}, {'E', 'C', 'D'}, {'F', 'E', 'D'}]

Для вышесказанного, желаемый результат:

[2, 0, 1]

поскольку в первом наборе A и B не найдены ни в одном из других наборов, для второго набора в этом наборе нет уникальных элементов, а для третьего набора F не найден ни в одном из других наборов.

Я думал о приближении к этому; найти пересечение каждого набора и вычесть длину пересечения из длины списка, но set.intersection(*), по-видимому, не работает со строками, поэтому я застрял:

set1 = {'A', 'B', 'C'}
set2 = {'C', 'D', 'E'}
set3 = {'D', 'E', 'F'}

targets = [set1, set2, set3]

>>> set.intersection(*targets)
set()

3 ответа

Решение

Ваш пример кода не работает, потому что он находит пересечение между всеми наборами, которое равно 0 (поскольку нигде не встречается элемент). Вы хотите найти разницу между каждым набором и объединением всех других наборов. Например:

set1 = {'A', 'B', 'C'}
set2 = {'C', 'D', 'E'}
set3 = {'D', 'E', 'F'}


targets = [set1, set2, set3]

result = []

for set_element in targets:
    result.append(len(set_element.difference(set.union(*[x for x in targets if x != set_element]))))

print(result)

(обратите внимание, что [x for x in targets if x != set_element] это просто набор всех остальных наборов)

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

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

from collections import Counter

def unique_count(sets):
    count = Counter()
    for s in sets:
        count.update(s)
    return [sum(count[x] == 1 for x in s) for s in sets]

Попробуйте что-то вроде ниже:

Получите симметричную разницу с каждым набором. Затем пересекаются с заданным входным набором.

def symVal(index,targets):
    bseSet = targets[index] 
    symSet = bseSet  
    for j in range(len(targets)):
        if index != j:
            symSet =  symSet  ^ targets[j] 
    print(len(symSet & bseSet))

for i in range(len(targets)):
    symVal(i,targets)
Другие вопросы по тегам