2

Total 関数としきい値パラメーターを使用して巨大なリストの長さを短縮する方法を探しています。For と If の使用は避けたいと思います (古い習慣から来ています)。

例: 「削減」したいリスト:{1,5,3,8,11,3,4}のしきい値で5

必要な出力:{6,11,11,7} つまり、リストの最初の部分で Total 関数を使用し、この関数の結果がしきい値よりも高いかどうかを調べます。そうであれば、Total 関数の結果を使用して、リストの次の部分に進みます。

もう 1 つの例は{1,1,1,1,1}、しきい値が の場合です5。結果は です{5}

ありがとう!

編集:動作していますが、かなり遅いです。より速くするためのアイデアはありますか?

編集2:ループのもの(シンプルでスマートではない)

For[i = 1, i < Length[mylist] + 1, i++,
sum = sum + mylist[[i]];
  If[sum > Threshold ,
result = Append[result , sum]; sum = 0;   ];   ];

EDIT 3:私は今、やるべき新しいことがあります。{{1,2}{4,9}{1,3}{0,5}{7,3}} 多かれ少なかれ同じ考えですが、リストの1番目と2番目の部分は、しきい値のものよりも高くなければなりません(両方) 。例 : If lst[[1]] and lst[[2]] > threshold do the summuation2D リストの各部分。Mr.Wizard の f2 関数をこのケースに適用しようとしましたが、うまくいきませんでした。より簡単な場合は、2 つの独立したリストを提供してf3[lst1_,lst2_,thres_]:= Reap[Sow@Fold[If[Element of the lst1 > thr && Element of the lst2, Sow@#; #2, # + #2] &, 0, lst1]][[2, 1]]、たとえばこの入力を使用できます。

EDIT 4:そうです、それは本当に明確ではありません。しかし、Min@# > thrステートメントの使用は完全に機能しています。

古いコード (醜く、まったくスマートではありません):

sumP = 0;
resP = {};
sumU = 0;
resU = {};
For[i = 1, i < Length[list1 + 1, i++,
 sumP = sumP + list1[[i]];
 sumU = sumU + list2[[i]];
 If[sumP > 5 && sumU > 5 ,
  resP = Append[resP, sumP]; sumP = 0;
  resU = Append[resU, sumU]; sumU = 0;
  ];
 ]

Mr.WizardによるNEWファスト:

   f6[lst_, thr_] := 
 Reap[Sow@Fold[If[Min@# > thr  , Sow@#1; #2, #1 + #2] &, 0, lst]][[2, 
   1]]

その ~40 倍高速です。どうもありがとう。

Thread[{resP, resU}] == f6[Thread[{list1,list2}], 5] True
4

3 に答える 3

2

Foldこの種の操作には、リンクされたリストまたは結果を蓄積する Sowand と組み合わせて使用​​することをお勧めします。Mathematicaのリストは配列であり、要素が追加されるたびに再割り当てする必要があるため、遅いです。ReapAppend

で始まります:

lst = {2, 6, 4, 4, 1, 3, 1, 2, 4, 1, 2, 4, 0, 7, 4};

リンクリストのバージョンは次のとおりです。

Flatten @ Fold[If[Last@# > 5, {#, #2}, {First@#, Last@# + #2}] &, {{}, 0}, lst]
{8, 8, 7, 7, 11, 4}

以前の出力は次のようになりFlattenます。

{{{{{{{}, 8}, 8}, 7}, 7}, 11}, 4}

Sowとを使用する方法は次のReapとおりです。

Reap[Sow @ Fold[If[# > 5, Sow@#; #2, # + #2] &, 0, lst]][[2, 1]]
{8, 8, 7, 7, 11, 4}

他の問題にも同様の方法を適用: (1) (2)

Sow @外側にFoldある は、アルゴリズムによって削除されるシーケンスの最後の要素を効果的に追加します。


簡単に比較できるように、関数としてパッケージ化されたメソッドと、george のメソッドを次に示します。

f1[lst_, thr_] := 
  Flatten @ Fold[If[Last@# > thr, {#, #2}, {First@#, Last@# + #2}] &, {{}, 0}, lst]

f2[lst_, thr_] := 
  Reap[Sow@Fold[If[# > thr, Sow@#; #2, # + #2] &, 0, lst]][[2, 1]]

george[t_, thresh_] := Module[{i = 0, s},
  Reap[While[i < Length[t], s = 0; 
     While[++i <= Length[t] && (s += t[[i]]) < thresh]; Sow[s]]][[2, 1]]
  ]

タイミング:

big = RandomInteger[9, 500000];

george[big, 5] // Timing // First

1.279

f1[big, 5] // Timing // First

f2[big, 5] // Timing // First

0.593

0.468

于 2012-10-02T17:53:35.997 に答える
1

これが300倍速い明らかなアプローチです。Prettyが常に最良であるとは限りません。

t = Random[Integer, 10] & /@ Range[2000];
threshold = 4;
Timing[
  i = 0; 
  t0 = Reap[
     While[i < Length[t], s = 0; 
     While[++i <= Length[t] && (s += t[[i]]) < threshold ]; 
     Sow[s]]][[2, 1]]][[1]]
Total[t] == Total[t0]
Timing[ t1 = 
   t //. {a___, b_ /; b < threshold, c_, d___} -> {a, b + c, d} ][[1]]
t1 == t0
于 2012-10-02T14:54:06.177 に答える
1

私はあなたの要求を次のように解釈します:

  • リスト内の要素がしきい値未満の場合、リスト内の次の要素に追加します。
  • リストが変更されなくなるまで、このプロセスを繰り返します。

したがって、しきい値5と入力リスト{1,5,3,8,11,3,4}については、

{6,3,8,11,3,4}
{6,11,11,3,4}
{6,11,11,7}

編集

私は今、あなたの問題に対するこの解決策をテストしました...

置換ルールを使用して操作を実装します。

myList = {1,5,3,8,11,3,4}
threshold = 5
mylist = mylist //. {a___, b_ /; b < threshold, c_, d___} :> {a, b+c, d}

ReplaceRepeated(記号化)の使用に注意してください//.

于 2012-10-01T15:03:08.587 に答える