2013-08-28 34 views
3

如何用两个或多个列表替换列表中的一个项目?我正在做分裂和索引,它看起来非常蟒蛇。用列表中的两个或多个替换一个项目的pythonic方式

我希望这样的事情存在:

values = [ "a", "b", "old", "c" ] 
[ yield ["new1", "new2"] if item == "old" else item for item in values ] 
// return [ "a", "b", "new1", "new2", "c" ] 
+0

哇,我们就其他答案进行了很好的讨论,每个人都删除了它们。奇怪。但是,谢谢大家! – gcb

回答

12

要做到这一点,最好的办法是使用itertools.chain.from_iterable

itertools.chain.from_iterable(
    ("new1", "new2") if item == "old" else (item,) for item in values) 

你所面临的“每个项目的多个项目”问题通过制作一个嵌套列表来解决,然后将其展开。通过使所有项目元组(我们只需要一个元素的单项元组),我们可以实现这一点。

当然,如果你需要一个列表而不是一个迭代器,可以通过调用list()来包装整个事物。

+2

@arshajii:如果“老”出现两次会发生什么?切片解决方案不会抓住他们,除非你循环 - 这只是工作(tm)。 – DSM

+2

另一个变化:'[我对于(('new1','new2')中的值的项目,如果item =='old'else(item,))]' –

+0

@DSM不错,这里还有+1 。 – arshajii

2

我认为你有正确的想法。但是,列表解析并不总是一个好的选择。

下面是使用列表连接的解决方案:

values = [ 'a', 'b', 'old', 'c' ] 

def sub1(values, old, new): 
    newvalues = [] 
    for item in values: 
     if item == old: 
      newvalues += new 
     else: 
      newvalues += [item] 
    return newvalues 

print sub1(values, 'old', ['new1', 'new2']) 

这里一个用发电机:

def sub2(values, old, new): 
    for item in values: 
     if item == old: 
      for i in new: 
       yield i 
     else: 
      yield item 

for i in sub2(values, 'old', ['new1', 'new2']): 
    print i 
+1

这并不比其他解决方案更好。 – Marcin

+2

@Marcin为什么不呢?我认为这是更清楚和更容易概括。 – idfah

+1

我认为你错了。 – Marcin

1

这里有一个一般的*多个值的解决方案,如要求通过OP here

subs = {'old':("new1", "new2"), 'cabbage':('ham','and','eggs')} 
itertools.chain.from_iterable(
    subs[item] if item in subs else (item,) for item in values) 

使用基于追加的方法不会变得更容易或更困难:

def sub1(values, subs): 
    newvalues = [] 
    for item in values: 
     if item in subs: 
      newvalues += subs[item] 
     else: 
      newvalues += [item] 
    return newvalues 

*如果你的老项目unhashable,那么这将无法工作,你就需要让他们可哈希或找出另一种数据结构。除了写出平等测试之外,你仍然会喜欢这一点。

+0

好点。唯一的情况是,当我选择后者时,就像你提到的那样,如果不得不检查一些webservice或者其他不可靠的结构。谢谢。非常感激。 – gcb

+1

@gcb我认为你很困惑。首先,没有任何结构不能以定义的或任意的顺序迭代。其次,web服务不是这样的结构。第三,第二种形式在任何情况下都没有好处,并且总是会变慢。 – Marcin

-1

好的。更多的功能性,但我不知道这是真的比较“Python化”:

reduce(operator.add, [ [x] if x != 'old' else ['new1','new2'] for x in values ]) 

真的一样另一个答案,只是减少而不是itertools。

Reduce是一种标准的函数式编程语言,所以它应该更明显。

itertools.chain.from_iterable很酷,但有点模糊。

+1

这比'itertools.chain.from_iterable()'效率低得多,因为它需要制作大量的中间列表。另外,'reduce()'和'operator.add()'只是重新创建'sum()'(由于我最初给出的原因,建议不要加入列表)。 –

相关问题