[英]Python Lambda Count/Loop Function
如果這是在其他地方回答的問題,我很抱歉。 通過 Google 和 Stackforum 搜索,我沒有找到任何可以推斷答案的內容; 但我覺得其中的一部分是我。
我正在嘗試將 lambdas 作為一個概念來解決,作為其中的一部分,我正在尋找使用它的方法。
所以,如果從函數的角度來看,這對於 lambda 來說是一件非常愚蠢的事情,請隨時讓我知道並解釋。 但無論哪種方式,我仍然想知道答案/仍然想知道如何使用 python 語言來做到這一點。
因此,出於測試目的,我有:
my_test = 'test_name'
testlist = ['test_name', 'test_name_dup', 'test_name_dup_1', 'test_name_dup_3']
我希望使用 lambda 來創建一個循環並返回不在測試列表中的第一個 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(雖然很酷)完全搞砸了我的腦袋。
Lambda 只是定義函數的另一種方式
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()
此時我們可以將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))()
希望這能讓您對自己可以做什么有所了解。 但是永遠不要這樣做,因為正如您所知,lambda 會使您的代碼非常難以閱讀。
在這種情況下不需要使用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
來解決這個問題,你還必須了解 itertools、迭代器、過濾器等。 我將建立在 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()
過程。 它接受兩個參數:一個謂詞和一個可迭代對象,並返回一個迭代器,只要謂詞為真,它就會從可迭代對象中刪除元素; 之后,返回每個元素。
對於可迭代對象,我正在傳遞count(1)
,這是一個迭代器,它生成從1
開始的無限數量的整數。
然后dropwhile()
開始消耗整數,直到謂詞為假; 這是傳遞內聯定義函數的好機會 - 這是我們的lambda
。 它依次接收每個生成的整數,檢查字符串 test_name_dup_# 是否存在於列表中。
當謂詞返回false
, dropwhile()
返回,我們可以通過調用next()
來檢索使其停止的值。
您可以將 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
你有點跑題了。 Lambda 只不過是“簡單”的函數,通常用於函數式編程中的快速語法。 它們是完美的配套內置函數“map”、“reduce”、“filter”,也適用於定義到itertools 中的更復雜的函數。 因此,對它們做的最有用的事情是生成/操作可迭代對象(尤其是列表)。 請注意,與列表推導式/普通循環相比,在大多數情況下,lambda 會減慢您的代碼速度,並且會使其更難閱讀。 下面是一個你想用 lambdas 做什么的例子。
>>> filter(lambda i: i!=(0 if len(testlist[i].split("_"))==3 else int(testlist[i].split("_")[-1])), range(len(testlist)))[0]
2
或者您可以通過 itertools 使用更復雜的函數。 無論如何,我強烈建議您不要將 lambda 用於此類任務,因為可讀性很差。 我寧願使用結構良好的 for 循環,它也更快。
[編輯]
為了證明 lambdas+builtins 並不比列表推導式快:考慮一個簡單的問題,因為 x in range(1000) 創建一個 x 移位 5 的列表。
$ python -m timeit 'map(lambda x: x>>5, range(1000))' 1000 個循環,最好的 3 個:每個循環225 微秒
$ python -m timeit '[x>>5 for x in range(1000)]'10000 個循環,最好的 3 個:每個循環99.1 usec
在沒有 lambda 的情況下,您的性能提高了 100% 以上。
我更喜歡列表理解或迭代器方法。 使我覺得很容易閱讀和維護的簡單襯墊。 坦率地說,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']
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.