如果这是其他地方的问题,我很抱歉。通过谷歌和Stackforum搜索我没有找到任何可以推断出答案的内容;但我觉得其中的一部分就是我。
我正在尝试将lambda作为一个概念,作为其中的一部分,我正在寻找使用它的方法。
所以,如果从功能的角度来看这是一个非常愚蠢的关于lambda的事情,请随时告诉我并解释。但无论哪种方式,我仍然想知道答案/仍然想知道如何使用python语言。
因此,出于测试目的,我有:
my_test = 'test_name'
testlist = ['test_name', 'test_name_dup', 'test_name_dup_1', 'test_name_dup_3']
我希望使用lambda来创建一个循环的函数,并返回第一个不在testlist中的test_name_#。该功能最终将应用于文件名,但出于测试目的,我不得不放弃实际读取文件名 - 给了我太多方法来搞砸了。
但my_test必须能够更改,测试列表将是文件路径列表。
所以,我正在寻找一个像:
这样的功能new_name = lambda x: my_test + '_' + str(x)
但是初始值应该是x = 1,并且它应该继续,直到new_name不在testlist中。似乎是:
bool(new_name not in testlist)
可能适用。
但我无法找到一种方法将初始x设置为1,并使用(x + 1)循环直到bool为真。
我知道这是可能的,因为我发现了一些在文件中循环的CRAZY lambda示例。我只是无法理解它们(并且没有任何方式可以与它们一起玩,因为它们处理的是编程级别之外的事情。
在相关的说明中,我可以在此循环的开头添加值吗? (即我可以检查test_name,然后检查test_name_dup,然后检查test_name_dup _#)?
提前感谢您的帮助! Lambdas(虽然非常酷)完全弄乱了我的脑袋。
答案 0 :(得分:6)
Lambdas只是定义函数的另一种方式
def foo(x):
return x + x
与
相同foo = lambda x: x + x
所以让我们从一个功能开始,做你想做的事情
def first_missing(items, base):
for number in itertools.count():
text = base + '_' + str(number)
if text not in items:
return text
首先要注意的是,你不能在lambda中使用循环。所以我们需要在没有循环的情况下重写它。相反,我们将使用递归
def first_missing(items, base, number = 0):
text = base + '_' + str(number)
if text not in items:
return text
else:
return first_missing(items, base, number + 1)
现在,我们也不能在lambda中使用if / else块。但我们可以使用三元表达式
def first_missing(items, base, number = 0):
text = base + '_' + str(number)
return text if text not in items else first_missing(items, base, number + 1)
我们不能在lambda中有局部变量,所以我们将使用一个技巧,默认参数
def first_missing(items, base, number = 0):
def inner(text = base + '_' + str(number)):
return text if text not in items else first_missing(items, base, number + 1)
return inner()
此时我们可以将内部重写为lambda
def first_missing(items, base, number = 0):
inner = lambda text = base + '_' + str(number): text if text not in items else first_missing(items, base, number + 1)
return inner()
我们可以组合两行来摆脱内部局部变量
def first_missing(items, base, number = 0):
return (lambda text = base + '_' + str(number): text if text not in items else first_missing(items, base, number + 1))()
最后,我们可以把整个事情变成一个lambda
first_missing = lambda: items, base, number = 0: (lambda text = base + '_' + str(number): text if text not in items else first_missing(items, base, number + 1))()
希望能让您深入了解自己能做些什么。但不是每个人都这样做。你可以告诉lambdas真的很难读。
答案 1 :(得分:2)
在这种情况下无需使用lambda
,简单的for
循环即可:
my_test = 'test_name_dup'
testlist = ['test_name', 'test_name_dup','test_name_dup_1', 'test_name_dup_3']
for i in xrange(1, len(testlist)):
if my_test + '_' + str(i) not in testlist:
break
print my_test + '_' + str(i)
> test_name_dup_2
如果你真的,真的想要使用lambda
来解决这个问题,你还需要学习迭代工具,迭代器,过滤器等等。我将以thg435的答案为基础,将其写成一个更惯用的时尚并解释它:
import itertools as it
iterator = it.dropwhile(
lambda n: '{0}_{1}'.format(my_test, n) in testlist,
it.count(1))
print my_test + '_' + str(iterator.next())
> test_name_dup_2
理解上述解决方案的关键在于dropwhile()
程序。它需要两个参数:谓词和可迭代,并返回一个迭代器,只要谓词为真,它就会从迭代中删除元素;之后,返回每个元素。
对于iterable,我传递count(1)
,这是一个从1
开始生成无限整数的迭代器。
然后dropwhile()
开始使用整数,直到谓词为假;这是传递内联定义函数的好机会 - 这是我们的lambda
。它依次接收每个生成的整数,检查列表中是否存在字符串test_name_dup_#。
当谓词返回false
时,dropwhile()
会返回,我们可以通过调用next()
来检索使其停止的值。
答案 2 :(得分:1)
您可以将lambda与itertools.dropwhile结合使用:
import itertools
n = itertools.dropwhile(lambda n: 'test_name_dup_%d' % n in testlist, range(1, len(testlist))).next()
关于你的上一个问题,你可以为名称编写一个生成器,例如:
def possible_names(prefix):
yield prefix
yield prefix + '_dup'
n = 0
while True:
n += 1
yield '%s_dup_%d' % (prefix, n)
然后使用dropwhile:
unique_name = itertools.dropwhile(lambda x: x in testlist, possible_names('test_name')).next()
print unique_name
答案 3 :(得分:1)
你有点偏离轨道。 Lambdas只不过是“简单”的函数,通常用于函数式编程中的快速语法。它们是完美的伴随内置函数“map”,“reduce”,“filter”,但也适用于itertools中定义的更复杂的函数。因此,最有用的是生成/操作可迭代对象(尤其是列表)。请注意,与列表推导/普通循环相比,lambdas会在大多数情况下减慢代码速度,并且会使其更难被阅读。这是一个你想用lambdas做什么的例子。
>>> filter(lambda i: i!=(0 if len(testlist[i].split("_"))==3 else int(testlist[i].split("_")[-1])), range(len(testlist)))[0]
2
或者你可以使用更复杂的函数和itertools。无论如何,我强烈建议你不要将lambdas用于这种任务,因为可读性很糟糕。我宁愿使用结构良好的for循环,这也更快。
<强> [编辑] 强>
要证明lambdas + builtins并不比列表推导更快:考虑一个简单的问题,对于范围内的x(1000),创建一个x移位5的列表。
$ python -m timeit'map(lambda x:x&gt;&gt; 5,range(1000))'1000循环,最好的3: 225 usec 每个循环
$ python -m timeit'[x&gt;&gt; 5 for x in range(1000)]'10000循环,最好的3: 99.1 usec 每循环
没有lambdas,你的性能提升了100%。
答案 4 :(得分:1)
我更喜欢list comprehension或iterator方法。轻松制作一个我认为非常容易阅读和维护的衬垫。坦率地说,lambdas属于某些地方,在这里我相信它不太优雅的解决方案。
my_test = 'test_name'
prefix = 'test_name_dup_'
testlist = ['test_name','test_name_dup','test_name_dup_1','test_name_dup_3']
from itertools import count
print next('%s%d' % (prefix, i) for i in count(1) if '%s%d' % (prefix, i) not in testlist)
这将返回序列中第一个未找到的实例,我认为这是最干净的。
当然,如果您更喜欢明确范围内的列表,可以将其修改为列表理解:
print ['%s%d' % (prefix, i) for i in xrange(0,5) if '%s%d' % (prefix, i) not in testlist]
返回:
['test_name_dup_0', 'test_name_dup_2', 'test_name_dup_4']