2017-05-19 2 views
2

Python3では、1行lambdaで計算する方法を探しています。のは、私は整数のリストのLCMを計算したいとしましょう、これはone line in Python2で行うことができますPython3で片面を減らす

print reduce(lambda a,b: a * b // gcd(a, b), mylist) 

は、1ラインのpython3(functools.reduceせず、暗黙の)で同じことを行うには、それは可能ですか?

Python3では、私はfiltermapおよびreduceがなくなったことを知っています。私は、彼らがより短く、より明確な形でのpython3に書き込むことができますので、私はもうfiltermapを必要と感じることはありませんが、私はいずれかを発見していない以外、私は、同様reduceのための素晴らしい代替を見つけることができると思いました。私はhaveを見たmanyの記事thatを提案tofunctools.reduceまたは "write out the accumulation loop explicitly"を使用していますが、私はfunctoolsをインポートせずに1行でやりたいと思います。

もしそれがもっと簡単になるなら、私はassociativecommutativeの両方の機能を使用することを述べるべきです。

  • f(1,f(2,f(3,4)))
  • f(f(1,2),f(3,4))
  • または任意の他の順序ので
+11

なぜ1行でやりたいのですか?それで、なぜ 'functools.reduce'を使いたいのですか?これらの要件はいずれも実用的ではないと思われます。 –

+4

Chrisのコメントに追加するために、 'reduce'は大域名空間から' functools'に正確に移動されました。 。 – Sneftel

+0

関連:私は結果を使用できるようにhttp://stackoverflow.com/questions/41524133/removing-duplicates-using-only-lambda-functions/41524134#41524134 –

答えて

1

を:それは計算のいずれかの場合は、リスト[1,2,3,4]の機能fと例えば、結果が良いだろう私は実際に何かを考え出した。パフォーマンスは保証されませんが、lambda機能を単独で使用する1ライナーです。functoolsまたはitertoolsの機能は1つではありません。

my_reduce = lambda l, f: (lambda u, a: u(u, a))((lambda v, m: None if len(m) == 0 else (m[0] if len(m) == 1 else v(v, [f(m[0], m[1])] + m[2:]))), l) 

これには、ここでそれが拡張され、やや読み取れない:

my_reduce = lambda l, f: (
    lambda u, a: u(u, a)) (
     (lambda v, m: None if len(m) == 0 
          else (m[0] if len(m) == 1 
             else v(v, [f(m[0], m[1])] + m[2:]) 
           ) 
     ), 
     l 
    ) 

テスト:

>>> f = lambda a,b: a+b 
>>> my_reduce([1, 2, 3, 4], f) 
10 
>>> my_reduce(['a', 'b', 'c', 'd'], f) 
'abcd' 

これがどのように機能するかをより深く説明についてthis other postを確認してください。

その最初のパラメータの関数であり、それ自体であろうlambda関数を用いて、再帰関数をエミュレートするかの原理。 lambda u, a: u(u, a)

この再帰関数を効果的に再帰呼び出しをトリガー機能の内部に埋め込まれています。

最後に、すべてのものは、そのパラメータのリストとバイナリの関数である機能に包まれています。あなたは、少なくとも一つの項目である配列を持っていると仮定し

my_reduce(mylist, lambda a,b: a * b // gcd(a, b)) 
+1

私はどれくらい時間がかかり、Yコンビネータを破棄するのだろうと思っていました。私は – Sneftel

+0

@Sneftel Iは@Sneftelが参照している推測[Yコンビネータ、型なしラムダ計算における固定小数点コンビネータの一つ(https://en.wikipedia.org/wiki/Fixed-point_combinator# Fixed_point_combinators_in_lambda_calculus)。 ([同名の会社](https://en.wikipedia.org/wiki/Y_Combinator_(会社))と混同しないでください([曖昧さ回避](https://en.wikipedia.org/wiki/Y_combinator) )) –

+1

O_O理解していない –

1

が長いあなたは、単にこのようrecursivly reduceを定義することができます:

def reduce(func, seq): return seq[0] if len(seq) == 1 else func(reduce(func, seq[:-1]), seq[-1]) 

ロングをあなたのコードを使用して


my_reduceバージョンは少し読みやすくなります:

def reduce(func, seq): 
    if len(seq) == 1: 
     return seq[0] 
    else: 
     return func(reduce(func, seq[:-1]), seq[-1]) 

これは再帰的ですが、Pythonは再帰呼び出しではあまりよくありません(遅いという意味で、再帰の制限は300アイテムより長いシーケンスを宣言できません)。はるかに高速な実装は次のようになります。

def reduce(func, seq): 
    tmp = seq[0] 
    for item in seq[1:]: 
     tmp = func(tmp, item) 
    return tmp 

しかし、ループのため、1行に入れることはできません。これは、副作用を使用して解決することができます。

def reduce(func, seq): d = {}; [d.__setitem__('last', func(d['last'], i)) if 'last' in d else d.__setitem__('last', i) for i in seq]; return d['last'] 

か:

のと同じです
def reduce(func, seq): d = {'last': seq[0]}; [d.__setitem__('last', func(d['last'], i)) for i in seq[1:]]; return d['last'] 

:速くする必要があります

def reduce(func, seq): 
    d = {} 
    for item in seq: 
     if 'last' in d: 
      d['last'] = func(d['last'], item) 
     else: 
      d['last'] = item 
    return d['last'] # or "d.get('last', 0)" 

が、それはリストするので、正確にニシキヘビではありません - 1行の実装での理解が、副作用のために使用されただけです。

関連する問題