2016-03-21 8 views
1

パイプオペレータはとても良いことです。 は例えば、私はまだEnum.reduceか何かに列挙を使用したい:パイプオペレータを使用した場合の最初の引数を取得

foo |> bar(...) |> Enum.reduce([], fn x, acc -> acC++ [Enum.at(<enumerable>, x)] end) 

その後、私は書くことを強制しています:として、パイプ演算子を使用する場合

enumerable = foo |> bar(...) 
Enum.reduce(enumerable, [], fn x, acc -> acC++ [Enum.at(enumerable, x)] end) 

は、最初の引数の構文糖を存在する可能性があり匿名機能で&1と同じですか?

+1

あなたの2番目の例では、 'Enum.reduce'の最初の引数として' enumerable'を忘れてしまったと思います。それでも、私はそれが何をすべきか私にはまだ明確ではありません。あなたは '[3、1、2]'のようなものを持っていて、 '[2,3、1]'に変身したいのですか? – tkowal

+0

はい、最初の議論を忘れました。編集された質問。 – jimmbraddock

答えて

3

Enum.reduce全体を1つの引数を取って名前を付けるという独自の関数に単純に移動して、誰もが何をしているのか理解できるようにすることをお勧めします。 rearrangeはわかりやすい名前ではありませんが、この手順がアプリでどのように使用されているかわかりません。

もう1つの解決策は、あなたの質問で言及したように匿名関数を使用することです。それは悪いですが、私は完全性のためにそれを言います。

&(Enum.reduce(&1, [], fn x, acc -> acC++ [Enum.at(&1, x)] end)) 

これは本当に複雑です。匿名関数内に匿名関数がありますが、関数内で&1を複数回使用できることが示されています。

最後に、acC++ [thing]は毎回ゼロからメモリ内のリストを再作成するので、本当に悪い考えです。それはO(n)です。 Enum.atも線形で、Enum.reduceなので、この関数はO(n^3)です。

代わりにfn x, acc -> [Enum.at(enumerable, x) | acc] endを実行し、最後に結果を取り消すことができます。

def rearrange(enumerable) do 
    enumerable 
    |> Enum.reduce([], fn x, acc -> [Enum.at(enumerable, x) | acc] end) 
    |> Enum.reverse 
end 

[thing | acc]はO(1)である。これは全体の手順をO(n^2)とし、それが何をしているのかについて合理的な時間です。

+0

私は、Elixirが通常の挿入操作をリストに持っていないのは不思議です。したがって私は+ +演算子を使用しています、私はそれを '[thing |リスト] 'を押して逆にします。それは遅いと判明した...いずれにしても、ありがとう! – jimmbraddock

+1

エリクサーのリストは、内部で単独でリンクされたリストです。それには限界がありますが、不変性を持って大きく働きます。例えば、あなたが 'long_list'を持っていて、別のものを前置しているときは、' [a | long_list] 'と' [b | long_list] '内部的には変更できないため、同じ' long_list'を指しています。 '[long_list] ++ [element]'でリストを変更できれば、この最適化が破られます。欠点はもちろん、追加が遅いのはO(n)であり、要素を追加するためだけに長いリスト全体をコピーする必要があることです。 – tkowal

関連する問題