【问题标题】:Iterating through list and using remove() doesn't produce desired result遍历列表并使用 remove() 不会产生所需的结果
【发布时间】:2020-07-14 02:42:05
【问题描述】:

我是一名编程新手,希望得到一些帮助以了解为什么以下算法会以特定方式运行。

我的目标是让函数读取包含单词(可以大写)的文本文件,去除空格,将项目拆分为单独的行,将所有大写的第一个字符转换为小写,删除所有单个字符(例如,“ a”、“b”、“c”等),并将生成的单词添加到列表中。所有单词都将成为列表中的单独项目以供进一步处理。

输入文件: 一个文本文件('sample.txt')包含以下数据 - “a apple b Banana c cherry”

期望的输出: [‘苹果’, ‘香蕉’, ‘樱桃’]

在我最初的尝试中,我尝试遍历单词列表以测试它们的长度是否等于 1。如果是,则将从列表中删除该单词,而其他单词则保留在列表中。这导致了以下不想要的输出:[None, None, None]

filename = ‘sample.txt’

with open(filename) as input_file:
    word_list = input_file.read().strip().split(' ')
    word_list = [word.lower() for word in word_list]
    word_list = [word_list.remove(word) for word in word_list if len(word) == 1]

print(word_list)

产生的非期望输出 = [None, None, None]

我的下一个尝试是遍历单词列表以测试它们的长度是否大于 1。如果是,则将该单词添加到列表中(将单个字符留在后面)。使用这种方法可以实现所需的输出。

filename = ‘sample.txt’

with open(filename) as input_file:
    word_list = input_file.read().strip().split(' ')
    word_list = [word.lower() for word in word_list]
    word_list = [word for word in word_list if len(word) > 1]

print(word_list)

生产所需的输出 = ['apple', 'banana', 'cherry']

我的问题是:

  1. 为什么最初的代码没有产生预期的结果,而它似乎是最合乎逻辑和最有效的?
  2. 实现预期结果的最佳“Pythonic”方式是什么?

【问题讨论】:

  • 你不应该在循环遍历列表时修改它。
  • list.remove 修改列表,但它不返回任何内容(它返回 None
  • FWIW,在我多年的 python 中,我从未使用过list.remove... 但是初学者尝试使用它似乎很常见!

标签: python list iteration


【解决方案1】:

得到输出的原因是

  1. 在循环遍历列表时,您正在从列表中删除项目
  2. 您正在尝试使用list.remove 的输出(它只是修改列表并返回None

您的最后一个列表理解 (word_list = [word_list.remove(word) for word in word_list if len(word) == 1]) 基本上等同于:

new_word_list = []
for word in word_list:
    if len(word) == 1:
        new_word_list.append(word_list.remove(word))
word_list = new_word_list

当你遍历它时,会发生这种情况:

# word_list == ['a', 'apple', 'b', 'banana', 'c', 'cherry']
# new_word_list == []

word = word_list[0]  # word == 'a'

new_word_list.append(word_list.remove(word))

# word_list == ['apple', 'b', 'banana', 'c', 'cherry']
# new_word_list == [None]

word = word_list[1]  # word == 'b'

new_word_list.append(word_list.remove(word))

# word_list == ['apple', 'banana', 'c', 'cherry']
# new_word_list == [None, None]

word = word_list[2]  # word == 'c'

new_word_list.append(word_list.remove(word))

# word_list == ['apple', 'banana', 'cherry']
# new_word_list == [None, None, None]

word_list = new_word_list

# word_list == [None, None, None]

最好的“Pythonic”方式(在我看来)是:

with open('sample.txt') as input_file:
    file_content = input_file.read()

word_list = []
for word in file_content.strip().split(' '):
    if len(word) == 1:
        continue
    word_list.append(word.lower())

print(word_list)

【讨论】:

  • 非常感谢您抽出宝贵时间了解我的(考虑不周的)第一种方法的逻辑。我现在明白了在遍历列表时从列表中删除项目的危险。
【解决方案2】:

在您的第一种方法中,您将word_list.remove(word) 的结果存储在无列表中。 Bcz list.remove() 方法只返回对给定列表执行操作。

您的第二种方法是实现目标的 Python 方式。

【讨论】:

    【解决方案3】:

    第二次尝试是最 Pythonic 的。第一个仍然可以通过以下方式实现:

    filename = 'sample.txt'
    
    with open(filename) as input_file:
        word_list = input_file.read().strip().split(' ')
    
    word_list = [word.lower() for word in word_list]
    
    for word in word_list:
        if len(word) == 1:
            word_list.remove(word)
    
    print(word_list)
    

    【讨论】:

      【解决方案4】:
      1. 为什么初始代码没有产生预期的结果 成为最合乎逻辑和最高效的?

      建议在迭代列表时不要更改列表。这是因为它正在迭代初始列表的视图,并且该视图将与原始视图不同。

      1. 实现预期结果的最佳“Pythonic”方法是什么?

      您的第二次尝试。但我会使用更好的命名约定,并且您的理解可以结合起来,因为您只在第一个中将它们设为小写:

      word_list = input_file.read().strip().split(' ')
      filtered_word_list = [word.lower() for word in word_list if len(word) > 1]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-31
        • 2016-05-08
        相关资源
        最近更新 更多