Поиск набора строк из списка пар (string, int) с максимальным значением int

#python #string #set #max

#python #строка #набор #макс

Вопрос:

У меня есть список (str,int) пар

list_word = [('AND', 1), ('BECAUSE', 1), ('OF', 1), ('AFRIAD', 1), ('NEVER', 1), ('CATS', 2), ('ARE', 2), ('FRIENDS', 1), ('DOGS', 2)]

Это в основном говорит о том, сколько раз каждое слово появлялось в тексте.

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

(set(['CATS', 'DOGS','ARE']), 2)

Решение, о котором я могу думать, — это перебор списка. Но есть ли какой-нибудь элегантный способ сделать это?

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

1. Вызов вашей переменной list может быть опасным.

2. Ах, спасибо, что указали. Я просто писал здесь для большей ясности. Редактирование сейчас

Ответ №1:

Два линейных сканирования, сначала для поиска максимального элемента:

 maxcount = max(map(itemgetter(1), mylist)) 
  

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

 maxset = {word for word, count in mylist if count == maxcount}, maxcount
  

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

 from collections import defaultdict

sets_by_count = defaultdict(set)

for word, count in mylist:
    sets_by_count[count].add(word)
  

За которым затем можно следовать, allcounts = sorted(sets_by_count.items(), key=itemgetter(0), reverse=True) чтобы получить list количество count, set пар, от наивысшего до наименьшего количества (с минимальной сортировкой, поскольку сортируется только количество элементов, равное количеству уникальных значений, а не все слова).

Ответ №2:

Преобразовать list в dict с ключом в качестве числа и значением в виде набора слов. Найдите max значение ключа и соответствующее ему значение

 from collections import defaultdict
my_list = [('AND', 1), ('BECAUSE', 1), ('OF', 1), ('AFRIAD', 1), ('NEVER', 1), ('CATS', 2), ('ARE', 2), ('FRIENDS', 1), ('DOGS', 2)]
my_dict = defaultdict(set)
for k, v in my_list:
    my_dict[v].add(k)

max_value = max(my_dict.keys())
print (my_dict[max_value], max_value)
# prints: (set(['CATS', 'ARE', 'DOGS']), 2)
  

Ответ №3:

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

Следующее довольно скучное решение примерно на ~ 55% быстрее, чем решение dict, и на ~ 70% быстрее, чем решения, основанные на понимании, основанные на предоставленных примерах данных (и моих реализациях, машине, бенчмаркинге и т. Д.)

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

 word_occs = [
    ('AND', 1), ('BECAUSE', 1), ('OF', 1), ('AFRIAD', 1), ('NEVER', 1),
    ('CATS', 2), ('ARE', 2), ('FRIENDS', 1), ('DOGS', 2)
]


def linear_scan(word_occs):
    max_val = 0
    max_set = None

    for word, occ in word_occs:
        if occ == max_val:
            max_set.add(word)

        elif occ > max_val:
            max_val, max_set = occ, {word}

    return max_set, max_val
  

Честно говоря, все они работают очень быстро, и в вашем случае удобочитаемость может быть более важной.