【问题标题】:Filter list by length of words按单词长度过滤列表
【发布时间】:2018-11-23 18:57:58
【问题描述】:

我正在尝试按单词的长度(在 4 到 8 个字符之间)逐行过滤包含单词的列表。这样如果输入文件有:

  • 你好
  • 通讯
  • 测试

输出文件是:

  • 你好
  • 测试

所以我有这个代码:

dir = "lower.lst"
dict = open(dir, 'r').readlines()
f=open('dictionary','w')
for word in dict:
  if len(word)>=4 & len(word)<=8:
    f.write(word)
f.close()
print(len(dict))

print(f)

但是输出文件保留了所有的单词。 顺便问一下,有没有更有效的方法来做到这一点?

【问题讨论】:

标签: python list filter


【解决方案1】:
  • 使用 with 语句自动关闭文件(即使遇到异常)。
  • Python 中的&amp; 真的只是为了玩转,使用and
  • 您实际上并不需要and,因为可以链接比较。 (len(word)&gt;=4 and len(word)&lt;=8 等同于 4 &lt;= len(word) &lt;= 8)。
  • 在您的问题中,您使用.readlines(),在这里我使用for line in fin:。无论哪种方式,生成的字符串都将以换行符结尾,因此您的长度测量值将减一。我通过在获取长度(len(line.strip()))之前剥离线来纠正这一点。 (您编写的代码应该省略'be',但保留'dog',因为它实际上是长度为4 的'dog\n'
  • 您说您的代码保留了所有单词。在我看来,您的代码应该可以省略'communication\n''be\n'。我可以想象如果文件中的'be\n' 后面有额外的空格('be \n' 的长度为 5,因为有两个空格),它可能会被保留。但似乎没有合乎逻辑的方式将'communication\n' 保存在您的输出文件中。您可能需要仔细检查它是否真的存在。

with open('lower.lst', 'r') as fin, open('dictionary', 'w') as fout:
    for line in fin:
        if 4 <= len(line.strip()) <= 8:
            fout.write(line)

【讨论】:

  • 一次打开​​两个文件的好方法,但你不应该在for line in fin:之前使用readlines()吗?
  • @PedroLobito:文件逐行迭代。 readlines() 首先将所有行缓冲到一个列表中,但如果您要做的只是遍历该列表,您应该剪掉中间人并直接进行迭代。如果文件大于工作内存,这一点尤其重要。 (这两种方法都会给出最后包含换行符的行。这会影响这个问题。)
【解决方案2】:

这样做的选择不止一种。

  1. 带有filter()内置函数

查看文档here

假设您有一个名为data 的字符串列表,那么:

data = ['hello', 'communication', 'be', 'dog', 'test']
filtered_list = filter(lambda x: len(x) > 4 and len(x) < 8, data)
print(filtered_list)

将返回:

Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux
>   
['hello']

您可以更改 lambda 函数以过滤不同的条件。过滤器将“捕获”每个返回 True 的元素。

  1. 带有列表理解

这可能是实现这一目标的最短方法。只需要做:

filtered_list = [x for x in data if len(x) > 4 and len(x) < 8]

【讨论】:

  • 当 OP 写“介于 4 到 8 个字符之间”时,我相信他的意思是具有包容性端点,因此也可以保留 4 和 8 的字长。如果是这样,您的&gt;&lt; 应该是&gt;=&lt;=。还有一种更清晰的写法是4 &lt;= len(x) &lt;= 8 没有and。最后,在您的回答中值得一提的是,OP 有一个额外的错误,因为他正在从文件中读取。他的话末尾有换行符,所以他的长度测量值相差了一个。
【解决方案3】:

List comprehension 确实允许您选择要从哪些元素构建您的列表。这是一个示例实现:

s = """
hello
communication
be
dog
test
"""

lst = [elm for elm in s.split() if (len(elm) >= 4 and len(elm) <= 8)]

print(lst)

输出:

['hello', 'test']

【讨论】:

    【解决方案4】:

    这就是你要找的吗?在这里,我使用带有 with 保留字的文件上下文管理器,并且我使用 and 而不是 cmets 中所述的 &amp;

    with open("lower.lst", "r") as f:
       o = [word for word in f if (len(word) >= 4 and len(word) <= 8)]
    
    with open("outfile.lst", "w") as f:
       f.write(o)
    

    很难知道这是否会完全符合您在输出文件中的意图。

    【讨论】:

      【解决方案5】:

      如果您将&amp; 替换为and,您的代码应该可以工作,即:


      dict = open("lower.lst", 'r').readlines()
      with open('dictionary','w') as f:
          for word in dict:
              if len(word)>=4 and len(word)<=8:
                  f.write(word)
      

      【讨论】:

      • readlines() 保留换行符,因此长度测试需要考虑到这一点:if 4 &lt;= len(word.strip()) &lt;= 8:。这也会影响写入:f.write(word)
      猜你喜欢
      • 1970-01-01
      • 2013-12-22
      • 2013-01-16
      • 1970-01-01
      • 2021-07-17
      • 1970-01-01
      • 2021-09-18
      • 2013-09-24
      • 2017-02-01
      相关资源
      最近更新 更多