2013-08-28 67 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()'(由於我最初給出的原因,建議不要加入列表)。 –

相關問題