5

これが他の場所で回答された質問である場合は申し訳ありません。Google と Stackforum を検索しても、答えを推定できるものは何も見つかりませんでした。しかし、私はその一部が私であるように感じます.

私は概念としてラムダを解決しようとしています。その一環として、ラムダを使用する方法を探しています。

だから、これが関数の観点からラムダを扱うのが非常に愚かなことである場合は、遠慮なく私に知らせて説明してください。しかし、いずれにせよ、私はまだ答えを知りたい/Python言語でこれを行う方法を知りたい.

だから、テスト目的のために私は持っています:

my_test = 'test_name'
testlist = ['test_name', 'test_name_dup', 'test_name_dup_1', 'test_name_dup_3']

ラムダを使用して、ループしてテストリストにない最初の test_name_# を返す 1 つの関数を作成しようとしています。この機能は最終的にファイル名に適用される予定ですが、テスト目的で、ファイル名を実際に読み取ることから離れなければなりませんでした。

ただし、my_test は変更できる必要があり、テスト リストはファイルパスのリストになります。

だから、私は次のような関数を探しています:

new_name = lambda x: my_test + '_' + str(x)

ただし、初期値は x = 1 である必要があり、new_name が testlist になくなるまで継続する必要があります。のように思える:

bool(new_name not in testlist)

何かうまくいくかもしれません。

しかし、最初の x を 1 に設定し、bool が true になるまで (x+1) でループする方法がわかりません。

ファイル内の行をループしているCRAZYラムダの例をいくつか見つけたので、これが可能であることを知っています。私はそれらを完全に理解することができませんでした (そして、彼らは私のプログラミングレベルの外のものを扱っていたので、それらをいじる方法がありませんでした.

関連して、このループの先頭に値を追加できますか? (つまり、test_name、次に test_name_dup、次に test_name_dup_# をチェックすることはできますか?)

助けてくれてありがとう!ラムダは(非常にクールですが)私の頭を完全に混乱させます。

4

5 に答える 5

6

ラムダは、関数を定義する別の方法です

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

最初に注意すべきことは、ラムダ内でループを使用できないことです。したがって、これをループなしで書き直す必要があります。代わりに、再帰を使用します。

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)

現在、ラムダで 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)

ラムダにローカル変数を含めることはできないため、トリック、デフォルトの引数を使用します。

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()

この時点で、内部をラムダとして書き換えることができます。

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()

2 つの行を結合して、内側のローカル変数を取り除くことができます。

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))()

そしてついに、全体をラムダにすることができます:

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))()

うまくいけば、何ができるかについての洞察を得ることができます。しかし、おわかりのように、ラムダはコードを非常に読みにくくする可能性があるため、決して実行しないでください。

于 2012-04-14T17:14:36.007 に答える
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

この問題に本当に本当に使用したい場合は、lambdaitertools、イテレータ、フィルタなどについても学ぶ必要があります。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()手順にあります。述語とイテレータの2つのパラメータを取り、述語がtrueである限り、イテレータから要素を削除するイテレータを返します。その後、すべての要素を返します。

イテレータについては、を渡します。count(1)これは、から始まる無限の数の整数を生成するイテレータです1

次にdropwhile()、述語がfalseになるまで整数の消費を開始します。これは、インラインで定義された関数を渡す良い機会です-そしてこれが私たちのlambdaです。生成された各整数を順番に受け取り、文字列test_name_dup_#がリストに存在するかどうかを確認します。

述語が戻るとfalsedropwhile()が返され、それを呼び出すことで、述語を停止させた値を取得できますnext()

于 2012-04-14T16:42:59.870 に答える
1

あなたは少し軌道から外れています。ラムダは「単純な」関数に他ならず、関数型プログラミングの高速構文でよく使用されます。これらは、組み込み関数「map」、「reduce」、「filter」に最適ですが、 itertoolsに定義されているより複雑な関数にも使用できます。したがって、それらを使用する最も便利なことは、反復可能なオブジェクト(特にリスト)を生成/操作することです。リスト内包表記/通常のループと比較した場合、ラムダはほとんどの場合コードの速度を低下させ、読みにくくすることに注意してください。ラムダで何をしたいのかの例を次に示します。

>>> filter(lambda i: i!=(0 if len(testlist[i].split("_"))==3 else int(testlist[i].split("_")[-1])), range(len(testlist)))[0]
2

または、itertoolsでより複雑な関数を使用することもできます。とにかく、読みやすさがひどいので、この種の割り当てにはラムダを使用しないことを強くお勧めします。よく構造化されたforループを使用したいのですが、これも高速です。

[編集]

ラムダ+ビルトインがリスト内包よりも高速ではないことを証明するには、単純な問題を考えます。range(1000)内のxについて、5だけシフトしたxのリストを作成します。

$ python -m timeit'map(lambda x:x >> 5、range(1000))' 1000ループ、ベスト3:ループあたり225 usec

$ python -m timeit'[x >> 5 for x in range(1000)]' 10000ループ、ベスト3:ループあたり99.1 usec

ラムダなしでパフォーマンスが100%以上向上します。

于 2012-04-14T16:59:11.200 に答える
1

ラムダを 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
于 2012-04-14T16:51:50.383 に答える
1

私は、リスト内包表記または反復子メソッドを好みます。読みやすく維持しやすいワンライナーを簡単に作成できます。率直に言って、ラムダはいくつかの場所に属しています。ここでは、あまりエレガントではないソリューションだと思います。

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']
于 2012-04-14T17:16:42.870 に答える