字典使用Python中的第一个字母索引文件

时间:2018-09-20 04:50:22

标签: python python-3.x dictionary

这是我应该做的:

编写一个函数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 :(得分:2)

您正在使它变得比原本要复杂的多,这正是挫折感的来源。实际的解决方案比您想象的要简单得多。

字典会跟踪自己的键。您不需要初始化任何东西。如果单词出现在字典中而不是字母,那么您可以立即添加一个新键。否则,您将使用已经存在的列表。

另一点是,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字符。尽管这对您的作业来说可能是正确的,但让我写出具有潜在问题的代码很烦人,因为以后会有那么多未知的问题要占用您的时间。为此,我将介绍使用regular expressions搜索单词的几种替代方法。

  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)

答案 1 :(得分:2)

您可能会想得太多。让我们列出必要的步骤(按照说明进行操作):

  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上都省略了错误处理;如果您打算将其转变为可部署的功能,那么这些将是重要的考虑因素。

答案 2 :(得分:1)

对我来说,这似乎更像Python。

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

删除非单词字符(对于非英语字符,您将需要一些更聪明的东西)可能足以完成此练习。在空格的任何组合上拆分意味着您将跳过换行符,制表符等。通过从结果中创建一个集合,重复项将自动删除。请注意,如果删除标点符号而不添加空格,则“不要”仍然是一个单词,但是“ something-else”变为“ somethingelse”,反之亦然。所以这可能是一个考虑因素。

您可以执行filter(lambda x: x, set(...))而不是if "" in terms:块,但是结果是相同的;此方法可能会导致您的术语集中包含空字符串,这会破坏dict的创建。

defaultdict可让您设置插入密钥的行为,因此无需检查密钥是否存在或预先创建密钥。

又一次编辑:我不认为从短语是否完全清楚这个问题是否要求所有字母都作为键出现,但是如果这样做,这意味着将d的初始化替换为defaultdict d = {l: [] for l in string.ascii_lowercase}