【问题标题】:How to replace every 2nd specific word in a list如何替换列表中的每个第二个特定单词
【发布时间】:2018-01-28 18:04:45
【问题描述】:

我在 python 中有这个列表:

['Banana', 'Apple', 'John', 'Banana', 'Food', 'Banana']

我想用Pear 替换每一秒的Banana(这应该是结果):

['Pear', 'Apple', 'John', 'Banana', 'Food', 'Pear']

我已经有了这个代码:

with open('text,txt') as f:
    words = f.read().split()

words_B = [word if word != 'Banana' else 'Pear' for word in words]

【问题讨论】:

    标签: python python-2.7 list replace


    【解决方案1】:

    这是一种通用方法,它通过倒数自上次替换后单词的出现次数来工作:

    from collections import defaultdict
    
    d = defaultdict(int)
    r = {
        'Banana': 'Pear',
    }
    
    fruits = ['Banana', 'Apple', 'John', 'Banana', 'Food', 'Banana']
    
    def replace(fruits, every, first=True):
      for f in fruits:
        # see if current fruit f should be replaced
        if f in r:
            # count down occurence since last change
            # -- start at 1 if first should be changed otherwise 0
            d.setdefault(f, int(not first))
            d[f] -= 1
            # if we have reached count down, replace
            if d[f] < 0:
                yield r[f]
                d[f] = every - 1 
                continue
        # otherwise append fruit as is
        yield f
    

    => list(replace(fruits, 2, first=True))

    ['Pear', 'Apple', 'John', 'Banana', 'Food', 'Pear']

    => list(replace(fruits, 2, first=False))

    ['Banana', 'Apple', 'John', 'Pear', 'Food', 'Banana']

    【讨论】:

      【解决方案2】:

      有点令人费解,但我想我会把它扔在那里。您可以使用itertools.cycle 使用辅助函数,该函数在 Banana 和 Pear 之间交替,其中元素是 Banana 或只是原始值,例如:

      from itertools import cycle
      
      data = ['Banana', 'Apple', 'John', 'Banana', 'Food', 'Banana']
      b2p = lambda L,c=cycle(['Banana', 'Pear']): next(c) if L == 'Banana' else L
      replaced = [b2p(el) for el in data]
      # ['Banana', 'Apple', 'John', 'Pear', 'Food', 'Banana']
      

      【讨论】:

        【解决方案3】:

        (只是要指出,您的预期结果并没有显示您用Pear 替换每一秒Banana,它显示您替换第一个和第三个Banana,而不是第二个。如果确实如此你想要什么,你可以在我下面的代码中将shouldReplace = False更改为shouldReplace = True。)

        MSeifert 的解决方案很巧妙,对我作为一个 Python 初学者来说非常有用,但只是指出另一种方法来改变你的列表是这样的:

        def replaceEverySecondInstance(searchWord, replaceWord):
            shouldReplace = False
            for index, word in enumerate(words):
                if word == searchWord:
                    if shouldReplace == True:
                        words[index] = replaceWord
                    shouldReplace = not shouldReplace
        

        跑步

        print(words)
        replaceEverySecondInstance('Banana', 'Pear')
        print(words)
        

        给出以下输出:

        ['Banana', 'Apple', 'John', 'Banana', 'Food', 'Banana']
        ['Banana', 'Apple', 'John', 'Pear', 'Food', 'Banana']
        

        【讨论】:

          【解决方案4】:

          您可以使用列表推导获取Banana 的所有索引,然后切片以获取这些索引中的每一秒,然后将相应的列表项设置为Pear

          >>> l = ['Banana', 'Apple', 'John', 'Banana', 'Food', 'Banana']
          >>> for idx in [idx for idx, name in enumerate(l) if name == 'Banana'][::2]:
          ...     l[idx] = 'Pear'
          >>> l
          ['Pear', 'Apple', 'John', 'Banana', 'Food', 'Pear']
          

          您也可以使用生成器表达式和itertools.islice,而不是理解和切片:

          >>> from itertools import islice
          >>> l = ['Banana', 'Apple', 'John', 'Banana', 'Food', 'Banana']
          >>> for idx in islice((idx for idx, name in enumerate(l) if name == 'Banana'), None, None, 2):
          ...     l[idx] = 'Pear'
          >>> l
          ['Pear', 'Apple', 'John', 'Banana', 'Food', 'Pear']
          

          另一种可能性,特别是如果您不想就地更改列表,则可以创建自己的生成器函数:

          def replace_every_second(inp, needle, repl):
              cnt = 0
              for item in inp:
                  if item == needle:    # is it a match?
                      if cnt % 2 == 0:  # is it a second occurence?
                          yield repl
                      else: 
                          yield item
                      cnt += 1          # always increase the counter
                  else:
                      yield item
          
          >>> l = ['Banana', 'Apple', 'John', 'Banana', 'Food', 'Banana']
          >>> list(replace_every_second(l, 'Banana', 'Pear'))
          ['Pear', 'Apple', 'John', 'Banana', 'Food', 'Pear']
          

          【讨论】:

          • 有没有办法在没有“特殊”自动替换命令的情况下做到这一点?
          • @JohnWinston 是的,我添加了一个使用生成器函数的解决方案。不确定这是否是您的意思,但它可以正常工作并且不会取代原件。 :)
          • @JohnWinston cnt 只计算 item == needle 为 True 的次数 - 连同 cnt % 2 == 0 它用于确定是否应该替换“第二次”出现。 yield 更复杂,并且已经在另一个 question + answer 中介绍过(很多细节)。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-02-12
          • 2015-05-12
          • 1970-01-01
          • 2020-06-16
          • 1970-01-01
          • 1970-01-01
          • 2018-10-30
          相关资源
          最近更新 更多