Словарь индексирует файл с первой буквой в Python - PullRequest
0 голосов
/ 20 сентября 2018

Вот что я должен сделать:

Написать функцию text_dictionary(file_name), которая принимает имя файла и возвращает словарь, в котором ключ представляет собой букву, а значение представляет собой список слов.из файла, который начинается с этого письма.Убедитесь, что список содержит только уникальные значения, все в нижнем регистре и не содержат знаков препинания.

И вот что у меня есть сейчас.

import string
string=string.ascii_lowercase
keys=[]
for letter in string:
    keys.append(letter)
def text_dictionary(file_name):
    with open(file_name,'r') as file:
        words=[]
        for line in file:
            words.append(line.rstrip())
            new_list=[]
            for i in words:
                new_list.append(i.lower())
                return new_list
            d={}
            for words in new_list:
                for i in range(25):
                    if word.startwith(new_list[i])==True:
                        d[words[i]]+=words
                return d
        print(d)

Код становился все длиннее и длиннееи я все еще не получил то, что хотел.Я даже не уверен, что я делаю и полезно ли это.Интересно, есть ли некоторые функции словаря, которые я не знаю.Действительно расстроен здесь.

Ответы [ 3 ]

0 голосов
/ 20 сентября 2018

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

  1. Создать словарь с каждой буквой алфавита в качестве ключа и пустым set в качестве значения.set используется для обеспечения уникальности.

  2. Откройте файл, удалите знаки препинания и строчные буквы и разделите его на список слов.

  3. Переберите слова в списке слов и добавьте каждое из них к соответствующему set в словаре на основе первой буквы.

  4. Преобразуйте все наборы обратно в списки ивернуть словарь.

Вот код:

import re
import string

def text_dictionary(file_name):
    letters = {x: set() for x in string.ascii_lowercase}

    with open(file_name,'r') as f:
        for word in re.sub(r"\W", " ", f.read().lower()).split():
            letters[word[0]].add(word)

    return {k: list(v) for k, v in letters.items()}


for k, v in sorted(text_dictionary("file.txt").items()):
    print(k, v)

Пример вывода (используя ваш вопрос в качестве ввода):

a ['all', 'a', 'accepts', 'and']
b ['begin']
c ['contains']
d ['do', 'dictionary']
e []
f ['file', 'from', 'function']
g []
h ['here']
i ['im', 'is']
j []
k ['key']
l ['lowercased', 'list', 'letter']
m ['marks', 'make']
n ['no', 'name']
o ['of', 'only']
p ['punctuation']
q []
r ['returns']
s ['supposed', 'sure']
t ['text_dictionaryfile_name', 'the', 'to', 'that']
u ['unique']
v ['values', 'value']
w ['what', 'write', 'where', 'words', 'with']
x []
y []
z []

Обратите внимание, чтоЯ пропустил обработку ошибок как для открытого файла, так и для потенциального KeyErrors;это было бы важным соображением, если бы вы планировали превратить это в развертываемую функцию.

0 голосов
/ 20 сентября 2018

Мне кажется, это немного более Pythonic.

import re
from collections import defaultdict


NON_LETTER = re.compile("[^\w\s]+")
WHITESPACE = re.compile(r"\s+")


def text_dictionary(filename):
    with open(filename, "r") as infile:
        terms = set(
            WHITESPACE.split(
                NON_LETTER.sub(
                    "", 
                    infile.read().lower()
                )
            )
        )

    if "" in terms:
        terms.remove("")

    d = defaultdict(lambda: [])

    for t in terms:
        d[t[0]].append(t)

    return d

Удаление несловарных символов (для неанглоязычных вам понадобится что-то более умное), вероятно, достаточно для этого упражнения.Разделение на любую комбинацию пробелов означает, что вы пропускаете новые строки, вкладки и т. Д. Создавая набор из результата, дубликаты автоматически удаляются.Обратите внимание, что если вы удалите пунктуацию без добавления пробела, «не» остается одним словом, но «что-то еще» становится «чем-то другим» и наоборот.Так что это может быть соображением.

Вы можете сделать filter(lambda x: x, set(...)) вместо блока if "" in terms:, но результат тот же;этот метод может привести к тому, что пустая строка окажется в вашем наборе терминов, что нарушит создание dict.

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

Еще одно редактирование: я не думаю, что из формулировки совершенно ясно, требует ли вопрос, чтобы все буквы присутствовали в качестве ключей, но если это так, все, что это означает, заменяетинициализация d как defaultdict с d = {l: [] for l in string.ascii_lowercase}.

0 голосов
/ 20 сентября 2018

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

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

Другой момент заключается в том, что модуль string предоставляет вам инструменты для разделения на оба whitespace и punctuation.Цена, которую вы платите, состоит в том, чтобы отфильтровывать некоторые пустые строки, но это тривиально.

Я бы рекомендовал хранить промежуточные результаты в set с вместо списков, чтобы обеспечить уникальность.Вы всегда можете конвертировать в списки в качестве последнего шага.

И использовать возвращаемые значения вместо распечаток в своих служебных функциях:

def text_dictionary(file_name):
    map = {}
    with open(file_name,'r') as file:
        for line in file:
            for word in line.split(string.whitespace + string.punctuation):
                if not word:
                    continue
                word = word.lower()
                if word[0] not in map:
                    map[word[0]] = set()
                map[word[0]].add(word)
    for key in map:
        map[key] = list(map[key])
    return map

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

Приложение 1: Преобразование словаря

Последний цикл заменяет наборы на месте списками: он несоздать новый объект словаря.Вы можете сделать то же самое с очень похожим циклом:

for key, value in map.items():
    map[key] = list(item)

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

Создание словарей обходится дешево, поэтомуможет быть быстрее использовать словарь для создания нового отображения вместо этого:

map = {key: list(value) for key, value in map.items()}

Приложение 2: Разделение слов

Алгоритм разделения слов, показанный выше, чрезвычайнопросто.Предполагается, что ваш файл будет содержать только печатные символы ASCII с хорошим поведением.Хотя это, вероятно, верно для вашего задания, меня раздражает написание кода, в котором есть потенциальные проблемы, потому что будет много неизвестных проблем, которые займут ваше время позже.С этой целью я представлю несколько альтернативных способов поиска слов с использованием регулярных выражений .

  1. Первая альтернатива - разделить на что-нибудь, что не 'т слово характер.Символ слова (в обычной строке) соответствует шаблону \w, который

    Соответствует символам слова Unicode;это включает в себя большинство символов, которые могут быть частью слова на любом языке, а также цифры и подчеркивание.Если используется флаг ASCII , сопоставляется только [a-zA-Z0-9_].

    Обратное значение \w равно \W, поэтому вы можете использовать его с re.split:

    for word in re.split(r'\W+', line):
    
  2. Второй вариант - дополнение к первому.Вместо разделения на шаблон, сопоставьте шаблон и используйте re.finditer, чтобы составить список слов для вас:

    for word in re.finditer(r'\w+', line):
    

Я в обоих случаях, этоСтоит отметить, что вам лучше предварительно скомпилировать выбранный шаблон, используя re.compile вместо того, чтобы каждый раз перекомпилировать шаблон.Наиболее эффективный способ установить шаблон - это либо глобально, либо с помощью аргумента функции по умолчанию.Таким образом, он будет оценен только один раз.Второй лучший вариант - сделать это перед блоком with, чтобы вы по крайней мере компилировали один раз для файла, а не для каждой строки.Глобальное или функциональное определение будет выглядеть как

pattern = re.compile(r'\w')  # or r'\W', as you prefer

В качестве аргумента по умолчанию:

def text_dictionary(file_name, pattern=re.compile(r'\w')):

Последний подход дает вам гибкость, если вы когда-нибудь решите изменить набор символов

В любом случае цикл будет

for word in pattern.split(line):  # or pattern.finditer(line)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...