Python: Как отсортировать значение словаря с помощью регулярных выражений

#python #regex #python-3.x #file #dictionary

#python #регулярное выражение #python-3.x #файл #словарь

Вопрос:

У меня есть два файла .txt, где он считывает их в словарь. Я хочу иметь опцию, при которой я мог бы сортировать значение (третья вкладка в файлах) в словаре от наивысшего к наименьшему, используя регулярное выражение.

Вот мои файлы: file1.txt

 file Marvel/GuardiansOfGalaxy 300 1
file DC/Batman 504 1
file GameOfThrones 900 0
file DC/Superman 200 1
file Marvel/CaptainAmerica 342 0
  

file2.txt

 file Science/Biology 200 1
file Math/Calculus 342 0
file Psychology 324 1
file Anthropology 234 0
file Science/Chemistry 444 1
  

Это предполагаемый результат:

 Game of Thrones: 900
DC/Batman: 404
Science/Chemistry: 444
Marvel/CaptainAmerica 342
Math/Calculus 342
...
  

Вот как пока выглядит мой код. У меня возникли проблемы с отображением данных в отсортированном виде на основе значения (третья вкладка) с использованием регулярных выражений. Функция чтения работает. Теперь все зависит только от отображения отсортированного словаря:

 def read():
    pattern = re.compile(r"file.py (. ).*? (d ) d ")

    data_files = []
    for file in glob.glob("*.txt"):
        with open(file, 'r') as filenames:
            data_files.append(dict(pattern.findall(filenames.read())))
    return data_files
  

Здесь я попытался отсортировать значения из словаря, используя re.findall и map(int,), но я получаю ошибку типа. Я не мог определить, где я ошибся. Это та часть, в которой мне в основном нужна помощь:

 def display(data_files):
    for lines in data_files:
        # print(lines)
        pattern_sort = re.findall(r"file.py (. ).*? (d ) d ", data_files)
        print(sorted(lines, key=lambda x: (map(int, pattern_sort))))
  

Я надеюсь, что это имеет смысл. Спасибо!

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

1. Зачем вам нужно регулярное выражение? Почему бы просто не разделить его, получить 3-е значение, поместить его в sort(), а затем упорядочить значения на основе этого?

2. @FailSafe Я использую регулярные выражения для анализа данных для последующего использования

3. Извините. Я должен быть более конкретным. Зачем вам нужно регулярное выражение для этой конкретной задачи? Это можно сделать, но может быть не оптимальным решением

4. Мне нужно регулярное выражение, чтобы найти количество просмотров в строке, а затем отсортировать его по остальным. У меня возникли проблемы с отображением сортировки с использованием карты в моей функции отображения. Я думаю, что для моей функции отображения я могу просто отсортировать и получить третьи данные, но как вы можете это сделать, не изменяя мою функцию чтения?

5. Есть ли причина, по которой вы вводите a dict вместо a list ? Если вы поместите его в список namedtuples , вы сможете легко сортировать по этому полю. В общем случае a dict не предназначен для сортировки. (Хотя вы можете использовать OrderedDict ). Через пару часов я смогу написать решение, но я просто хочу знать, нужно ли вам использовать dict .

Ответ №1:

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

Пожалуйста, обратите внимание, что мне пришлось изменить символ табуляции на ||| since repl.it это не позволяет мне использовать символ табуляции в файлах. Вам нужно будет заменить ||| на t в приведенном ниже скрипте.

Смотрите, как это выполняется здесь

 import glob
from collections import defaultdict, OrderedDict

d = defaultdict(list)

def read():
  for files in glob.glob('*.txt'):
    with open(files, 'r') as f:
      for line in f:
        r = line.rstrip('n').split('|||')
        d[r[2]].append(r)

def display(d):
  od = OrderedDict(sorted(d.items(), reverse=True))
  for k,v in od.items(): print(k,v)

read()
display(d)
  

Вывод для приведенного выше скрипта приведен ниже:

 900 [['file', 'GameOfThrones', '900', '0']]
504 [['file', 'DC/Batman', '504', '1']]
444 [['file', 'Science/Chemistry', '444', '1']]
342 [['file', 'Marvel/CaptainAmerica', '342', '0'], ['file', 'Math/Calculus', '342', '0']]
324 [['file', 'Psychology', '324', '1']]
300 [['file', 'Marvel/GuardiansOfGalaxy', '300', '1']]
234 [['file', 'Anthropology', '234', '0']]
200 [['file', 'DC/Superman', '200', '1'], ['file', 'Science/Biology', '200', '1']]
  

Различные выходы

Переход print(k,v) на другой формат приведет к другому результату, как вы отметили в комментариях ниже. Например:

 print(k, [x[1] for x in v])
  

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

 900 ['GameOfThrones']
504 ['DC/Batman']
444 ['Science/Chemistry']
342 ['Marvel/CaptainAmerica', 'Math/Calculus']
324 ['Psychology']
300 ['Marvel/GuardiansOfGalaxy']
234 ['Anthropology']
200 ['DC/Superman', 'Science/Biology']
  

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

1. Есть ли способ просто показать второе и третье значение? Я думаю, это то, что я могу использовать regex, чтобы просто отображать их или нет?

2. @smokingpenguin вы можете изменить способ display печати выходных данных

3. Основная причина, по которой я решил использовать регулярные выражения, заключается в том, чтобы убедиться, что определенный формат строки распознается в файлах. Если строка в текстовом файле имеет вид «hello.py / Marval / Бросок 43 4» Это не будет засчитано. Имеет ли это смысл?

4. @smokingpenguin непонятно. Вы должны обновить свой вопрос, чтобы включить всю соответствующую информацию. Мы оба решили вопрос на основе информации, предоставленной вами в вопросе.

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

Ответ №2:

Как сказал FailSafe regex , для этого нет причин, поэтому я использовал split вместо этого. Я добавлю regex решение этой проблемы позже, но вот как это сделать без regex .

 import glob
from collections import namedtuple

# A lightweight object.
# Makes it easier to sort.
Entry = namedtuple("Entry", "name views")

def read():
    data_files = []
    for file in glob.glob("*.txt"):
        with open(file, 'r') as infile:
            for line in infile.read().splitlines():
                # For each line in the file

                # Split apart our line
                line = line.split(' ')
                # Create an Entry object with our name and views
                # and add it to our data_files.
                data_files.append(Entry(line[1], int(line[2])))
    return data_files
result = read()

# We want to sort based on views so return the views.
def sort_meth(x):
    return x.views
    # If you want to sort by views then name you can do
    # return (x.views, x.name)

# Sort our result
result.sort(key=sort_meth, reverse=True)
for entry in result: # Print each entry
  print(entry.name, entry.views)
  

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

1. smokingpenguin — оригинальный плакат. Не беспокойтесь. Мне нравятся оба опубликованных решения.

2. Ха-ха, не беспокойся, приятель. Надеюсь, он все понимает.

3. @Error-SyntacticalRemorse Это тоже работает! Я все же хотел бы посмотреть, как регулярные выражения могут использоваться в вашем коде.

4. @smokingpenguin Если решение словаря работает для вас, вы можете придерживаться того, что знаете. Можно ли с уверенностью предположить, что конец вашей строки / строки всегда будет одинаковым, и изменится только начало?

5. @smokingpenguin серьезно, здесь это так не нужно. Вы бы выполняли дополнительную работу без причины. Используйте регулярные выражения там, где это уместно. Да, мы знаем, что вы хотите учиться, но иногда бывают случаи, когда дополнительные шаги просто глупы. Регулярное выражение для этого было бы полностью упрощенным для любого, у кого есть опыт, который можно использовать для 2-секундного сообщения.