是否有一种简单的方法可以确定值数组的局部最小值和最大值。例如
Element Value Note
1 1
2 3
3 5
4 6
5 7 max
5 5
6 4 min
7 6
8 9
9 10 max
10 8
11 7
12 5 min
13 10
所以定义的数组如下:
let arr = [|1;3;5;6;7;5;4;6;9;10;8;7;5;10|]
会识别
mins = [|4;5|]
和
maxs = [|7;10|]
它可以是列表或序列以及数组。两个问题
THX
答案 0 :(得分:10)
这似乎是...... Seq.windowed的工作! < cue superhero music>
let arr = [|1;3;5;6;7;5;4;6;9;10;8;7;5;10|]
let _,mins,maxs =
arr |> Seq.windowed 3 |> Seq.fold (fun (i,mins,maxs) [|a;b;c|] ->
if a>b&&b<c then (i+1, i::mins, maxs)
elif a<b&&b>c then (i+1, mins, i::maxs)
else (i+1, mins, maxs)) (1,[],[])
arr |> Seq.iteri (fun i x -> printfn "%2d: %2d" i x)
printfn "mins %A" mins
printfn "maxs %A" maxs
(*
0: 1
1: 3
2: 5
3: 6
4: 7
5: 5
6: 4
7: 6
8: 9
9: 10
10: 8
11: 7
12: 5
13: 10
mins [12; 6]
maxs [9; 4]
*)
答案 1 :(得分:2)
根据Brian的回答,我稍微偏爱这个版本:
let arr = [|1;3;5;6;7;5;4;6;9;10;8;7;5;10|]
let find_min_max input =
let windows = Seq.windowed 3 input
let mins = Seq.filter (fun [|a;b;c|] -> a>b && b<c) windows
|> Seq.map (fun [|a;b;c|] -> b)
let maxs = Seq.filter (fun [|a;b;c|] -> a<b && b>c) windows
|> Seq.map (fun [|a;b;c|] -> b)
mins, maxs
let mins, maxs = find_min_max arr
printfn "mins %A" mins
printfn "maxs %A" maxs
答案 2 :(得分:2)
基于Massif的回答,这是基于Brian的回答,我可能会将过滤器滚动并映射成一个:
let find_min_max input =
let windows = Seq.windowed 3 input
let mins = Seq.choose (fun [|a;b;c|] -> if a>b && b<c then Some(b) else None) windows
let maxs = Seq.choose (fun [|a;b;c|] -> if a<b && b>c then Some(b) else None) windows
mins, maxs
:)
答案 3 :(得分:1)
我认为编写
是微不足道的for x from 0 to size-2:
if (a[x] > a[x+1] && a[x+1] < a[x+2]) // also, there should be bound checking
//a[x+1] is a min!
minima.cram(x+1)
if (a[x] < a[x+1] && a[x+1] > a[x+2]) // also, there should be bound checking
//a[x+1] is a max!
maxima.cram(x+1)
或者我过度简化了?
答案 4 :(得分:0)
如果你正在寻找一个功能性的例子,你可能会(在Ruby中)
def derivative_signs(list)
(0..list.length-2).map { |i| (list[i+1] - list[i]) <=> 0 }
## <=> is the "rocketship" operator which is basically: be -1 if number is negative
## be 0 if number is zero
## be 1 if number is positive
## Alternatively, one could use x / x.abs, with an exception if x == 0
end
def derivative(list)
(0..list.length-2).map { |i| list[i+1] - list[i] }
end
来自微积分,最小值/最大值是一阶导数改变符号的时间。因此,可以查看derivative_signs(arr)
并查找所有符号更改。
first_derivative_signs = derivative_signs(arr)
# => [1, 1, 1, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1]
或者,您也可以
second_derivative = derivative(derivative_signs(arr))
在您提供的列表中,您将获得:
[0, 0, 0, -2, 0, 2, 0, 0, -2, 0, 0, 2]
很明显,二阶导数-2
的值是最大值,二阶导数2
的值是最小值。二阶导数的索引是原始列表的索引+ 1.因此second_derivative[4]
-2
对应arr[5]
(7),这是最大值。
为什么我们第二次做一个“正常”导数,而不是衍生数据?
这是因为当一个值连续重复两次时,你会得到不想要的行为。
例如,考虑
[1, 3, 6, 6, 7, 5, 4, 6, 9, 10, 8, 7, 5, 10]
# first_derivative_signs => [1, 1, 0, 1, -1, -1, 1, 1, 1, -1, -1, -1, 1]
# second_derivative_signs => [0, -1, 1, -1, 0, 1, 0, 0, -1, 0, 0, 1]
# second_derivative => [0, -1, 1, -2, 0, 2, 0, 0, -2, 0, 0, 2]
请注意,second_derivative_signs
会向我们抛出一些“虚假”的最小值/最大值,而second_derivative
,当我们只检查-2
和2
时,这是好的。
答案 5 :(得分:0)
我会使用Seq.pairwise
来获取每个号码及其前身。然后,您可以计算每个数字与其前任之间的差异,以获得所有值之间的差异。
在第三步中,您将检查差异并查找符号更改。当符号发生变化时,您知道之前符号更改的值是极值(最小值或最大值)。
我完全不知道F#,但第一步应该是这样的:
let diffs = Seq.pairwise arr |> Seq.map (-)