Приведение Counter() к диктовке или списку

У меня проблема (подробнее здесь (Лучший способ сравнить несколько ключевых значений [списков] и вернуть кратные?))

Краткое содержание:

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

Я хочу получить: Все значения, присутствующие более чем в одном списке Как часто эти значения присутствуют (например, если они присутствуют 2 раза в каждом списке, я хочу выдать эти 2, а не общее количество вхождений во всех списках!) И, наконец: я хочу подсчитать значения, которые находятся более чем в одном списке, но не в каждом списке.

Установка:

В цикле я добавляю списки данных, которые я хочу сравнить, с «главным» списком:

[
['Limerick (IRE)', 'Fairyhouse (IRE)', 'Gowran Park (IRE)', 'Galway (IRE)', 'Roscommon (IRE)', 'Ballinrobe (IRE)', 'Roscommon (IRE)', 'Downpatrick (IRE)', 'Ballinrobe (IRE)', 'Curragh (IRE)', 'Naas (IRE)', 'Curragh (IRE)', 'Galway (IRE)', 'Cork (IRE)', 'Punchestown (IRE)', 'Galway (IRE)', 'Tipperary (IRE)', 'Curragh (IRE)', 'Gowran Park (IRE)', 'Cork (IRE)', 'Galway (IRE)', 'Killarney (IRE)', 'Curragh (IRE)', 'Roscommon (IRE)', 'Limerick (IRE)', 'Newton Abbot', 'Bangor-on-Dee', 'Bangor-on-Dee'],

['Newton Abbot', 'Worcester', 'Ffos Las', 'Worcester', 'Newton Abbot', 'Hereford', 'Worcester', 'Chepstow', 'Newton Abbot', 'Bangor-on-Dee', 'Stratford', 'Ffos Las', 'Huntingdon', 'Newton Abbot', 'Bangor-on-Dee'],

['Aintree', 'Market Rasen', 'Market Rasen', 'Newcastle', 'Stratford', 'Hexham', 'Cartmel', 'Stratford', 'Cartmel', 'Cartmel','Bangor-on-Dee', 'Stratford', 'Ffos Las', 'Huntingdon', 'Newton Abbot', 'Bangor-on-Dee', 'Killarney (IRE)']
]

Может быть только 2 списка, или 20, или больше для сравнения.

Теперь я пытаюсь получить множители с помощью Counter() и извлечь наиболее распространенные из них. ПСЕВДОКОД:

        doubles= Counter()
        for w in testlist[1]:
            doubles[w] = testlist[2].count(w)
        result4 = results3.most_common(2)
        result5 = [result4[0]]

Но это не работает так, как предполагалось: потому что оно подсчитывает вхождения кратных в один список! (если в списке 1 слово/число есть один раз, а во втором - пять раз, я все равно хочу получить на выходе только 1 - не шесть и не пять. Если в List[1 - два раза ] и 3 раза в List[2], я хочу **получить 2 (+ число/слово!) **в качестве вывода и так далее)

Вторая проблема, которая у меня есть: количество списков варьируется. Может быть 2, может быть 20. Итак, testlist[1] - это просто заполнитель - мне нужно будет проверить все 20 списков (или любое другое число) на наличие слова/числа, которое есть в каждом списке.

У меня в голове не укладывается, как это сделать. Надеюсь, вы можете мне помочь

Редактировать

  • Добавлен третий список для примера
  • Ожидаемый результат: Сравнивая эти списки, я хотел бы получить что-то вроде:
  • Бангор-он-Ди: 3 (потому что есть во всех 3-х списках), 2 (потому что есть во всех списках минимум два раза)
  • Килларни: 2 (потому что он есть только в 2 из этих списков), 1 (потому что он есть хотя бы один раз в этих списках)

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

Karl Knechtel 26.01.2023 14:37

У меня нет кода, который я могу скопировать — код, который у меня есть, не делает того, что я хочу. Два приведенных выше списка являются подлинными выходными данными, сгенерированными lopp. Нельзя просто скопировать цикл сюда, потому что он получает данные из базы данных... Могу ли я изменить какой-либо элемент, чтобы он соответствовал минимальному воспроизводимому примеру?

Phil 26.01.2023 14:42

Учитывая приведенный выше ввод, какой результат вы ищете. Пример не помешал бы. Концептуально, что, если вы примените collections.Counter() к каждому из списков, а затем сравните эти результаты друг с другом?

JonSG 26.01.2023 14:45

@JonSG Еще не пробовал. Как я могу сравнить результаты коллекций друг с другом? Извините за вопрос, самоучка и очень любитель

Phil 26.01.2023 15:11

«У меня нет кода, который я могу скопировать — код, который у меня есть, не делает того, что я хочу». Код, который вы показываете, вообще непригоден для использования. Вы даже назвали это псевдокодом. Пока неясно, как этот код должен относиться к вопросу. Это искренняя попытка решить проблему с помощью конкретной конкретной проблемы, о которой вы спрашиваете? это расплывчатый набросок того, что, по вашему мнению, может содержать правильный код? Только что?

Karl Knechtel 26.01.2023 15:35

Например: "Настройка: В цикле" - тут же, почему бы не показать цикл?

Karl Knechtel 26.01.2023 15:35

Потому что цикл в основном: for _ в SQL-Result: list.append(track) - как объяснено в связанном посте, где я спросил, будет ли лучше добавление к dict или list - и как лучше всего было бы архивировать моя цель. Я не уверен, действительно ли это полезно для вопроса, как сравнивать эти списки?

Phil 26.01.2023 18:30
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
7
57
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

arr1 = ['Newton Abbot', 'Worcester', 'Ffos Las', 'Worcester', 'Newton Abbot', 'Hereford', 'Worcester', 'Chepstow',
        'Newton Abbot', 'Bangor-on-Dee', 'Stratford', 'Ffos Las', 'Huntingdon', 'Newton Abbot', 'Bangor-on-Dee']
arr2 = ['Aintree', 'Market Rasen', 'Market Rasen', 'Newcastle', 'Stratford', 'Hexham', 'Cartmel', 'Stratford',
        'Cartmel', 'Cartmel', 'Bangor-on-Dee', 'Stratford', 'Ffos Las', 'Huntingdon', 'Newton Abbot', 'Bangor-on-Dee']

all_lists = [arr1, arr2]

occurences = {}

for x in all_lists[0]:
    # check if x is in all_lists
    x_in_all_lists = True
    counts = []
    for arr in all_lists:
        if x not in arr:
            x_in_all_lists = False
            break
        counts.append(arr.count(x))
    # get the least number of times x occurs in the lists of all_lists
    if x_in_all_lists:
        occurences[x] = min(counts)

for k, v in occurences.items():
    print(f'{k}\t{v}')

Выход:

Newton Abbot    1
Ffos Las        1
Bangor-on-Dee   2
Stratford       1
Huntingdon      1

Спасибо, это работает для примера выше! Я немного отредактировал вопрос, как было предложено в комментариях. Будет ли это работать, если я добавлю больше списков в all_lists, а all_lists[0] не будет соответствовать следующим спискам? Я мог бы составить список всех треков и сделать это all_lists[0], а затем использовать ваш скрипт для их подсчета... это сработает?

Phil 26.01.2023 15:09

@Phil Поскольку вы сказали, что вам нужны только элементы, которые появляются во всех списках, работает только выборка элементов из all_lists[0]. Потому что, если элемента нет в all_lists[0], он не в каждом списке в all_lists.

Tario You 27.01.2023 08:49
Ответ принят как подходящий

перед любой оптимизацией я бы разбил эту задачу на три шага,

  1. подсчитать количество вхождений каждого ключа в каждой строке
  2. объединить счетчики на основе ключа
  3. распечатайте результаты на основе того, что мы узнаем о подсчетах после слияние их
import collections
import json

data = [
    ['Limerick (IRE)', 'Fairyhouse (IRE)', 'Gowran Park (IRE)', 'Galway (IRE)', 'Roscommon (IRE)', 'Ballinrobe (IRE)', 'Roscommon (IRE)', 'Downpatrick (IRE)', 'Ballinrobe (IRE)', 'Curragh (IRE)', 'Naas (IRE)', 'Curragh (IRE)', 'Galway (IRE)', 'Cork (IRE)', 'Punchestown (IRE)', 'Galway (IRE)', 'Tipperary (IRE)', 'Curragh (IRE)', 'Gowran Park (IRE)', 'Cork (IRE)', 'Galway (IRE)', 'Killarney (IRE)', 'Curragh (IRE)', 'Roscommon (IRE)', 'Limerick (IRE)', 'Newton Abbot', 'Bangor-on-Dee', 'Bangor-on-Dee'],
    ['Newton Abbot', 'Worcester', 'Ffos Las', 'Worcester', 'Newton Abbot', 'Hereford', 'Worcester', 'Chepstow', 'Newton Abbot', 'Bangor-on-Dee', 'Stratford', 'Ffos Las', 'Huntingdon', 'Newton Abbot', 'Bangor-on-Dee'],
    ['Aintree', 'Market Rasen', 'Market Rasen', 'Newcastle', 'Stratford', 'Hexham', 'Cartmel', 'Stratford', 'Cartmel', 'Cartmel','Bangor-on-Dee', 'Stratford', 'Ffos Las', 'Huntingdon', 'Newton Abbot', 'Bangor-on-Dee', 'Killarney (IRE)']
]

## ---------------------
## Gather the per row counts
## ---------------------
data_counted = [
    dict(collections.Counter(row))
    for row
    in data
]
#print(json.dumps(data_counted, indent=4, sort_keys=True))
## ---------------------

## ---------------------
## merge the rows on name
## ---------------------
data_counted_combined = {}
for row in data_counted:
    for name, count in row.items():
        target = data_counted_combined.setdefault(name, []) ## make sure this key is initialized
        target.append(count)
#print(json.dumps(data_counted_combined, indent=4, sort_keys=True))
## ---------------------

## ---------------------
## Generate the final result (sorted for fun)
## ---------------------
for key, value in sorted(data_counted_combined.items(), key=lambda x: x[0]):
    print(f"\"{key}\" appears in { len(value) } list(s) a minimum of { min(value) } times.")
## ---------------------

Это приводит к следующему:

"Aintree" appears in 1 list(s) a minimum of 1 times.
"Ballinrobe (IRE)" appears in 1 list(s) a minimum of 2 times.
"Bangor-on-Dee" appears in 3 list(s) a minimum of 2 times.
"Cartmel" appears in 1 list(s) a minimum of 3 times.
"Chepstow" appears in 1 list(s) a minimum of 1 times.
"Cork (IRE)" appears in 1 list(s) a minimum of 2 times.
"Curragh (IRE)" appears in 1 list(s) a minimum of 4 times.
"Downpatrick (IRE)" appears in 1 list(s) a minimum of 1 times.
"Fairyhouse (IRE)" appears in 1 list(s) a minimum of 1 times.
"Ffos Las" appears in 2 list(s) a minimum of 1 times.
"Galway (IRE)" appears in 1 list(s) a minimum of 4 times.
"Gowran Park (IRE)" appears in 1 list(s) a minimum of 2 times.
"Hereford" appears in 1 list(s) a minimum of 1 times.
"Hexham" appears in 1 list(s) a minimum of 1 times.
"Huntingdon" appears in 2 list(s) a minimum of 1 times.
"Killarney (IRE)" appears in 2 list(s) a minimum of 1 times.
"Limerick (IRE)" appears in 1 list(s) a minimum of 2 times.
"Market Rasen" appears in 1 list(s) a minimum of 2 times.
"Naas (IRE)" appears in 1 list(s) a minimum of 1 times.
"Newcastle" appears in 1 list(s) a minimum of 1 times.
"Newton Abbot" appears in 3 list(s) a minimum of 1 times.
"Punchestown (IRE)" appears in 1 list(s) a minimum of 1 times.
"Roscommon (IRE)" appears in 1 list(s) a minimum of 3 times.
"Stratford" appears in 2 list(s) a minimum of 1 times.
"Tipperary (IRE)" appears in 1 list(s) a minimum of 1 times.
"Worcester" appears in 1 list(s) a minimum of 3 times.

Большое спасибо! Работал с этим кодом и думаю, что получил то, что хотел :)

Phil 03.02.2023 23:26

Вот разбивка кода:

  1. Подсчитайте частоту каждого слова в каждом списке (counters)
  2. Соберите все слова из всех списков и сгенерируйте набор слов, которые мы можем ожидать появления в любом из этих списков (all_words)
  3. Определите словарь maxFreqDict, который сопоставляет слова в all_words кортежам (a,b) где
    a = количество списков, в которых встречается это слово
    b = минимальное количество вхождений этого слова (среди списков, где оно встречается)
    Инициализируйте каждое a значением 0 и b некоторым большим числом, которое мы позже уменьшим.
  4. Прогоняем counters через функцию редукции, где для каждого возможного word мы обновляем кортеж (a,b), если word присутствует в текущем списке, иначе ничего не делаем.
  5. Распечатайте результат (конечное состояние maxFreqDict)

Примечание: more_itertools — это установленный пакет, который расширяет возможности встроенного itertools. more_itertools.flatten(array2d) можно заменить на itertools.chain(*array2d), если вы не хотите устанавливать дополнительный пакет.

from collections import Counter
from functools import reduce
from more_itertools import flatten
from pprint import pprint

lists = [
    ['Limerick (IRE)', 'Fairyhouse (IRE)', 'Gowran Park (IRE)', 'Galway (IRE)', 'Roscommon (IRE)',
     'Ballinrobe (IRE)', 'Roscommon (IRE)', 'Downpatrick (IRE)', 'Ballinrobe (IRE)', 'Curragh (IRE)',
     'Naas (IRE)', 'Curragh (IRE)', 'Galway (IRE)', 'Cork (IRE)', 'Punchestown (IRE)', 'Galway (IRE)',
     'Tipperary (IRE)', 'Curragh (IRE)', 'Gowran Park (IRE)', 'Cork (IRE)', 'Galway (IRE)', 'Killarney (IRE)',
     'Curragh (IRE)', 'Roscommon (IRE)', 'Limerick (IRE)', 'Newton Abbot', 'Bangor-on-Dee', 'Bangor-on-Dee'],
    ['Newton Abbot', 'Worcester', 'Ffos Las', 'Worcester', 'Newton Abbot', 'Hereford', 'Worcester', 'Chepstow',
        'Newton Abbot', 'Bangor-on-Dee', 'Stratford', 'Ffos Las', 'Huntingdon', 'Newton Abbot', 'Bangor-on-Dee'],
    ['Aintree', 'Market Rasen', 'Market Rasen', 'Newcastle', 'Stratford', 'Hexham', 'Cartmel', 'Stratford', 'Cartmel',
        'Cartmel', 'Bangor-on-Dee', 'Stratford', 'Ffos Las', 'Huntingdon', 'Newton Abbot', 'Bangor-on-Dee', 'Killarney (IRE)']
]


# counter the frequency of each word in each list
counters = [Counter(l) for l in lists]
# find all the unique words across all lists
all_words = set(flatten(c.keys() for c in counters))

def reduceFunc(maxFreqDict: dict[str, tuple[int, int]], curCounter: Counter) -> dict[str, tuple[int, int]]:
    for word in maxFreqDict.keys():
        if word in curCounter:
            # listFeq: in how many lists this word appears
            # wordFreq: the min number of occurrences of this word (among the lists that it appears in) 
            listFreq, wordFreq = maxFreqDict[word]
            minWordFreq = min(wordFreq, curCounter[word])
            maxFreqDict[word] = (listFreq + 1, minWordFreq)
        else:
            pass
    return maxFreqDict

# start with a large number as the frequency of each word
# so we can find the actual frequency in reduceFunc using min()
maxFreqDict = {word: (0, 1e9) for word in all_words}
res = reduce(reduceFunc, counters, maxFreqDict)

pprint(res)

Это должно привести к следующему результату:

{'Aintree': (1, 1),
 'Ballinrobe (IRE)': (1, 2),
 'Bangor-on-Dee': (3, 2),
 'Cartmel': (1, 3),
 'Chepstow': (1, 1),
 'Cork (IRE)': (1, 2),
 'Curragh (IRE)': (1, 4),
 'Downpatrick (IRE)': (1, 1),        
 'Fairyhouse (IRE)': (1, 1),
 'Ffos Las': (2, 1),
 'Galway (IRE)': (1, 4),
 'Gowran Park (IRE)': (1, 2),        
 'Hereford': (1, 1),
 'Hexham': (1, 1),
 'Huntingdon': (2, 1),
 'Killarney (IRE)': (2, 1),
 'Limerick (IRE)': (1, 2),
 'Market Rasen': (1, 2),
 'Naas (IRE)': (1, 1),
 'Newcastle': (1, 1),
 'Newton Abbot': (3, 1),
 'Punchestown (IRE)': (1, 1),        
 'Roscommon (IRE)': (1, 3),
 'Stratford': (2, 1),
 'Tipperary (IRE)': (1, 1),
 'Worcester': (1, 3)}

Другие вопросы по теме