Wolfram mathematica 查找Mathematic列表中大于阈值的第一个元素
我想知道如何获得大于给定阈值的(已排序)列表的第一个元素 我不太了解Mathematica中的列表操作函数,也许有人能给我一个有效的技巧。做你需要的事情,并且会保持一致,尊重列表的原有顺序:Wolfram mathematica 查找Mathematic列表中大于阈值的第一个元素,wolfram-mathematica,Wolfram Mathematica,我想知道如何获得大于给定阈值的(已排序)列表的第一个元素 我不太了解Mathematica中的列表操作函数,也许有人能给我一个有效的技巧。做你需要的事情,并且会保持一致,尊重列表的原有顺序: Select[list, # > threshold &, 1] 例如: In[1]:= Select[{3, 5, 4, 1}, # > 3 &, 1] Out[1]= {5} 您可以在第二个参数中提供所需的任何阈值或标准函数 第三个参数只指定一个(即第一个)匹配的元素
Select[list, # > threshold &, 1]
例如:
In[1]:= Select[{3, 5, 4, 1}, # > 3 &, 1]
Out[1]= {5}
您可以在第二个参数中提供所需的任何阈值或标准函数
第三个参数只指定一个(即第一个)匹配的元素
希望有帮助 您可能还需要查看TakeWhile[]和纵向[]
使用
Select
可以解决问题,但如果您关心效率,这是一个糟糕的解决方案<代码>选择遍历列表的所有元素,因此所需时间与列表长度成线性关系。
既然您说列表是有序的,那么使用它会更好,它将在列表大小为对数的时间内工作。表达式(edit:由于我编写的上一个表达式没有正确处理列表中的重复元素,我做了一个小的调整。另一个编辑:当阈值本身作为重复元素出现在列表中时,这仍然不起作用,请参阅注释):将为您提供所需元素的索引。如果所有元素都小于阈值,则将得到列表的长度加上一。
p、 在使用
BinarySearch
之前,不要忘记调用Needs[“Combinatica'”
list /. {___, y_ /; y > 3, ___} :> {y}
比如说
{3, 5, 4, 1} /. {___, y_ /; y > 3, ___} :> {y}
{5}
Joe在他的文章中正确地指出,人们期望二进制搜索技术比
Select
更快,后者似乎只是进行线性搜索,即使列表已排序:
ClearAll[selectTiming]
selectTiming[length_, iterations_] := Module[
{lst},
lst = Sort[RandomInteger[{0, 100}, length]];
(Do[Select[lst, # == 2 &, 1], {i, 1, iterations}] // Timing //
First)/iterations
]
(出于演示目的,我任意将阈值设置为2)
但是,Combinatica中的BinarySearch
函数a)不合适(它返回的元素与请求的元素不匹配,但不是第一个元素(最左边的),这就是问题所在
为了获得大于阈值的最左侧元素,给定一个有序列表,我们可以递归地执行以下操作之一:
binSearch[lst_,threshold_]:= binSearchRec[lst,threshold,1,Length@lst]
(*
return position of leftmost element greater than threshold
breaks if the first element is greater than threshold
lst must be sorted
*)
binSearchRec[lst_,threshold_,min_,max_] :=
Module[{i=Floor[(min+max)/2],element},
element=lst[[i]];
Which[
min==max,max,
element <= threshold,binSearchRec[lst,threshold,i+1,max],
(element > threshold) && ( lst[[i-1]] <= threshold ), i,
True, binSearchRec[lst,threshold,min,i-1]
]
]
产生
因此,速度更快,伸缩性更好
实际上没有必要编译它,但我还是编译了
总之,不要对长列表使用Select
我的回答到此结束。下面是一些关于手工或通过Combinatica包进行二进制搜索的评论
我比较了一个(编译的)短例程进行二进制搜索的速度与combinatica
中的BinarySearch
的速度。请注意,这并不符合问题的要求(也不符合BinarySearch
中的BinarySearch
),我上面给出的代码确实如此
二进制搜索可以迭代地实现为
binarySearch = Compile[{{arg, _Integer}, {list, _Integer, 1}},
Module[ {min = 1, max = Length@list,
i, x},
While[
min <= max,
i = Floor[(min + max)/2];
x = list[[i]];
Which[
x == arg, min = max = i; Break[],
x < arg, min = i + 1,
True, max = i - 1
]
];
If[ 0 == max,
0,
max
]
],
CompilationTarget -> "C",
RuntimeOptions -> "Speed"
];
让我们比较两个二进制搜索例程。重复50000次:
Needs["Combinatorica`"]
Do[binarySearch[2, lst], {i, 50000}] // Timing
Do[BinarySearch[lst, 2], {i, 50000}] // Timing
(*
{0.073437, Null}
{4.8354, Null}
*)
所以手写的更快,因为实际上二进制搜索只访问列表中的6-7个点来获取这些参数(例如,
{500000,250000,125000,62500,31250,15625,23437}
),很明显,区别只是开销;例如,BinarySearch
可能更通用,或者没有编译。仅供将来参考,从v10开始,您可以使用
它增加了一些细节,例如返回缺少的[]
或默认值
从文档中:
SelectFirst[{e1,e2,…},crit]
给出第一个ei
,如果没有找到,则crit[ei]
为True
,或者缺少[“NotFound”]
SelectFirst[{e1,e2,…},crit,default]
如果没有ei
,则给出default
,从而crit[ei]
为True
对于您的具体情况,您可以使用:
SelectFirst[list, # > threshold &]
为什么需要天花板?而且,这不会返回第一个(最左边的)匹配元素。我写了一些东西,在我的答案中使用二进制搜索来获得最左边的元素。我将
上限
函数更改为下限
函数,以正确处理列表中的重复元素。这是必需的,因为如果阈值介于元素n和n+1之间,则二进制搜索
返回n+1/2.我编写的代码工作得很好,确实返回了第一个(最左边的)元素,该元素大于阈值(请求的不是匹配的元素)。它也比他在回答中提供的代码@acl简单得多。奇怪的是,lst={1,3,3,3,3,3,4,5};Floor[BinarySearch[lst,3]+1]
给出了6和lst[[6]]不大于阈值,但与我下面给出的binarySearch
例程相同(但速度大约快50倍)。我的答案中的复杂代码只是带有稍微修改的终止条件的二进制搜索(以便实际获得比阈值大的最左边的元素)。或者至少它基本上正确地找到了正确的元素:)你是对的@acl,很抱歉怀疑你。如果阈值作为循环元素出现在列表中,BinarySearch
从循环序列的中间给出一个索引,这是不好的。太糟糕了,我们必须编写Mathematica已经提供的函数的我们自己的版本,只是因为它没有给我们控制权关于终止条件。感谢投票。更令人遗憾的是,即使一个人需要的正是BinarySearch
所做的,手工编写和编译会使它更快。但这可能是因为BinarySearch
是Combinatica
的一部分,而不是一个内置函数er但请尝试tmp=Sort[RandomInteger[{01000},100000]
binarySearch = Compile[{{arg, _Integer}, {list, _Integer, 1}},
Module[ {min = 1, max = Length@list,
i, x},
While[
min <= max,
i = Floor[(min + max)/2];
x = list[[i]];
Which[
x == arg, min = max = i; Break[],
x < arg, min = i + 1,
True, max = i - 1
]
];
If[ 0 == max,
0,
max
]
],
CompilationTarget -> "C",
RuntimeOptions -> "Speed"
];
lst = Sort[RandomInteger[{0, 100}, 1000000]];
Needs["Combinatorica`"]
Do[binarySearch[2, lst], {i, 50000}] // Timing
Do[BinarySearch[lst, 2], {i, 50000}] // Timing
(*
{0.073437, Null}
{4.8354, Null}
*)
SelectFirst[list, # > threshold &]