2010-04-02 60 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

相关问题