我正在寻找一种通过Total函数和阈值参数来减少巨大列表长度的方法。我想避免使用For和If(来自旧习惯)。
示例:
列出我想要“减少”:{1,5,3,8,11,3,4}
,其阈值为5
。
我想要的输出:{6,11,11,7}
这意味着我在列表的第一部分使用Total函数,并查看此函数的结果是否高于我的阈值。如果是这样,我使用Total函数的结果并转到列表的下一部分。
另一个示例是{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; ]; ];
编辑3:我现在有一件新事要做。
我现在必须使用像{{1,2}{4,9}{1,3}{0,5}{7,3}}
这样的2D列表
它或多或少是相同的想法,但列表的第一和第二部分必须高于thresold的东西(两者都)。
示例:对于2D列表的每个部分,If lst[[1]] and lst[[2]] > threshold do the summuation
。我试图调整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]]
。
编辑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;
];
]
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
答案 0 :(得分:2)
我建议您使用Fold
进行此类操作,并结合链接列表或Sow
和Reap
来累积结果。 Append
速度很慢,因为 Mathematica 中的列表是数组,每次附加元素时都必须重新分配。
从:
开始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}
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
答案 1 :(得分: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
(符号//.
)。
答案 2 :(得分:1)
这是一种显而易见的方法,速度提高了300倍......漂亮并不总是最好的。
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