2010-04-02 33 views
2

我正在尋找一種簡潔而實用的樣式,將函數應用於元組的一個元素並返回Python中的新元組。將函數應用於Python中的列表中的一個元素

例如,對於下面的輸入:

inp = ("hello", "my", "friend") 

我希望能夠得到以下的輸出:

out = ("hello", "MY", "friend") 

我想出了兩種解決方案,我很不滿意用。

一個使用更高階的函數。

def apply_at(arr, func, i): 
    return arr[0:i] + [func(arr[i])] + arr[i+1:] 

apply_at(inp, lambda x: x.upper(), 1) 

一個使用列表解析(這個假設元組的長度是已知的)。

[(a,b.upper(),c) for a,b,c in [inp]][0] 

有沒有更好的方法?謝謝!

+1

您可以將您的元組轉換爲(可變)列表,更改它的第n個元素,並在需要時將其轉換回元組。但是如果你只需要迭代新的元組,爲什麼不創建一個簡單的產生每個元素的生成器,除了第i個元素,它會產生func(元素)?只是一個想法,但。 – 2010-04-02 06:29:08

+0

當然,我可以做mylist [idx] = func(mylist [idx]),但我想要一個功能風格的單線解決方案,以便我可以在return語句中使用它。 – Mathieu 2010-04-02 06:38:19

+0

你的第一個解決方案是清晰,簡潔,直接。如果它困擾你,那暗示它解決了錯誤的問題。 (順便說一句,arr [0:i]可以是arr [:i]。) – 2010-04-02 07:42:01

回答

1

我評論支持你的第一個片段,但這裏有一些其他的方式備案:

(lambda (a,b,c): [a,b.upper(),c])(inp) 

(不會在Python 3.x的工作)和:

[inp[0], inp[1].upper(), inp[1]] 
+0

鑑於我所需要的是採用由函數返回的a,b,c和返回a,b,c和b變換,我想你的lambda解決方案接近我想要的精神。 這將是很好的語法糖這樣的: 返回inp作爲a,b.upper(),c 原因我不完全滿意我的原始apply_at函數是我想要應用的轉換僅存在作爲一種方法,迫使我使用匿名函數,而不像列表理解解決方案。 你的第二個解決方案似乎需要一個inp的中間變量,如果它不在它自己的函數中。 – Mathieu 2010-04-02 08:27:24

+0

以下是Python 3.0中的工作嗎? (lambda a,b,c:[a,b.upper(),c])(* inp) – Mathieu 2010-04-02 08:35:07

+0

是的,它應該。好吧,我如何處理你所描述的問題:用兩條語句:a,b,c = inp;返回a,b.upper(),c。不幸的是,Python不是像Scheme這樣的面向表達式的,但這就是它的意圖。 – 2010-04-02 19:34:07

2
>>> inp = "hello", "my", "friend" 
>>> index = 1 
>>> inp[:index] + (str.upper(inp[index]),) + inp[index + 1:] 
('hello', 'MY', 'friend') 

看起來很簡單,你可能需要知道的唯一的事情就是使單個元素的元組,做(ELT)

2

也許有些」這樣嗎?

>>>inp = ("hello", "my", "friend") 
>>>out = tuple([i == 1 and x.upper() or x for (x,i) in zip(t,range(len(t)))]) 

>>> out 
('hello', 'MY', 'friend') 

注:不是(x,i) in zip(t, range(len(t)))我應該用枚舉函數的思想:(i,x) in enumerate(t)

製作多一點一般:
而不是硬編碼1,我們可以將它放在一個變量。
此外,通過爲此目的使用元組,我們可以將該函數應用於多個索引處的元素。

>>>inp = ("hello", "my", "friend") 
>>>ix = (0,2) 
>>>out = tuple([i in ix and x.upper() or x for (i, x) in enumerate(t)]) 

>>> out 
('HELLO', 'my', 'FRIEND') 

另外,我們可以 「替代」 的zip()/枚舉()的地圖(),在像

out = tuple(map(lambda x,i : i == 1 and x.upper() or x, inp, range(len(inp)))) 

編輯:(涉及有關指定函數來評論適用):
可能是簡單的東西如:

>>> f = str.upper # or whatever function taking a single argument 
>>> out = tuple(map(lambda x,i : i == 1 and f(x) or x, inp, range(len(inp)))) 

既然我們談到申請我們應該提一下condition and if_true or if_false這個構造,它不是,而是的替代品,它代替了在其他語言中發現的if/else三元運算符。限制是該函數不能返回等於False的值(例如,None,0,0.0,'')。避免這個問題的建議是Python 2。5只及以上,使用真正的if-else三元運算符,如圖戴維Kirby的答案(注意when_true if condition else when_false語法該運營商的)

+0

很好地使用邏輯「and」和「or」!指定要應用的函數的方法也是需要的。一種方法是指定一個函數作爲參數,但這會強制用戶使用匿名函數(lambda),如果要應用的函數是一種方法...... – Mathieu 2010-04-02 06:55:52

+1

請參閱我的答案,瞭解更多pythonic版本 - python 2。5開始有一個if-else三元運算符,所以你不需要使用和&或,並且枚舉函數爲序列中的每個元素返回一個元組(索引,值),所以你不需要使用範圍和len。 – 2010-04-02 07:14:50

+0

@Dave Kirby:謝謝你的提示!我知道枚舉,但不是2.5+中的if-else三元運算符。現在我會更頻繁地使用這個操作符,特別是這可能不會受到我提到的警告(重新設定False值)。讓我+1年的答案教我這個新的詭計! – mjv 2010-04-02 07:26:08

6

下面是對可迭代的工作並返回發電機的版本:

>>> inp = ("hello", "my", "friend") 
>>> def apply_nth(fn, n, iterable): 
... return (fn(x) if i==n else x for (i,x) in enumerate(iterable)) 
... 
>>> tuple(apply_nth(str.upper, 1, inp)) 
('hello', 'MY', 'friend') 

您可以擴展此使,而不是一個位置,你可以給它位置的列表:

>>> def apply_at(fn, pos_lst, iterable): 
... pos_lst = set(pos_lst) 
... return (fn(x) if i in pos_lst else x for (i,x) in enumerate(iterable)) 
... 
>>> ''.join(apply_at(str.upper, [2,4,6,8], "abcdefghijklmno")) 
'abCdEfGhIjklmno' 
+0

你的解決方案非常優雅和Pythonic。謝謝! – Mathieu 2010-04-02 08:28:14

0

,如果你想在數組中的某一功能適用於每一個元素,我不明白,通過一些測試,或者如果你想要它的應用程序將函數應用於元組中某個索引處的任何元素。所以,我有編碼兩種算法:

這是算法(Python編寫),我會使用類似方案的功能性的語言來解決這個問題:

此功能將通過id識別元素可識別並應用func並返回一個列表,該元素已更改爲func的輸出。

def doSomethingTo(tup, id): 
    return tuple(doSomethingToHelper(list(tup), id)) 

def doSomethingToHelper(L, id): 
    if len(L) == 0: 
     return L 
    elif L[0] == id: 
     return [func(L[0])] + doSomethingToHelper(L[1:], id) 
    else: 
     return [L[0]] + doSomethingToHelper(L[1:], id) 


該算法將數組的索引處找到的元素,並應用func它,並堅持它放回原來的索引元組

:它會爲每一個元素識別爲 id做到這一點
def doSomethingAt(tup, i): 
    return tuple(doSomethingAtHelper(list(tup), i, 0)) 

def doSomethingAtHelper(L, index, i): 
if len(L) == 0: 
     return L 
elif i == index: 
     return [func(L[0])] + L[1:] 
else: 
     return [L[0]] + doSomethingAtHelper(L[1:], index, i+1) 
+0

這將在Python中大量低效 - 如果你有一個長度爲N的列表,它會創建並銷燬N個列表,每個列表的長度爲N.它也會遞歸到N的深度,這可能會超過Python堆棧的限制。 – 2010-04-02 07:11:55

+0

@Dave Kirby:user189637的確請求了一種功能性方法。我看到的大部分功能都不起作用,因此我的解決方案。至於創建和銷燬N多個列表,這就是我學習函數式編程所要做的。此外,函數式編程意味着在並行計算環境中運行,因此在串行計算環境中效率較低。 – inspectorG4dget 2010-04-02 22:29:33

0

我也喜歡戴夫科比給出了答案。然而,作爲公共服務公告,我想說這不是元組的典型用例 - 這些數據結構起源於Python,作爲將數據(參數,參數)移入和移出函數的手段。 ..它們不適合程序員在應用程序中用作通用數組類似的數據結構 - 這就是列表存在的原因。自然地,如果你需要元組的只讀/不可變特性,這是一個公平的參數,但考慮到OP問題,這應該已經用列表完成 - 請注意如何有額外的代碼來拉動將元組分開並將結果放在一起和/或需要暫時轉換爲列表並返回。

+0

我故意選擇了元組。正如我在Darius Bacon的解決方案中所評論的那樣,我想要轉換的元組起源於函數中的返回。 – Mathieu 2010-04-02 08:57:11

+0

我同意,我的原始問題應該更詳細。對不起,這是我在stackoverflow上的第一個問題。 – Mathieu 2010-04-02 08:59:05

相關問題