我正在尝试从下一个数组中找到2个最大数字的索引和值:
{24,64,3,54,2,80,20}
我不能使用sort方法,因为我需要保留项目的索引。
在此示例中,结果应该是。
max1 = 80
max2 = 64
indexMax1 = 5
indexMax2 = 1
任何帮助将不胜感激。
答案 0 :(得分:2)
这是我们可以使用reduce
和一些慷慨的解构分配来实现的方法。注意如果输入的元素少于两(2)个,则max2
返回None
–
const None =
Symbol ('None')
const max2 = ([ a = None, b = None, ...rest ]) =>
a === None || b === None
? None
: rest .reduce
( ([ m1, m2 ], val, i) =>
val > m1.val
? [ { val, i: i + 2 }, m1 ]
: val > m2.val
? [ m1, { val, i: i + 2 } ]
: [ m1, m2 ]
, b < a
? [ { val: a, i: 0 }, { val: b, i: 1 } ]
: [ { val: b, i: 1 }, { val: a, i: 0 } ]
)
console .log
( max2 ([])
// None
, max2 ([ 1 ])
// None
, max2 ([ 24, 64, 3, 54, 2, 80, 20 ])
// [ { val: 80, i: 5 }, { val: 64, i: 1 } ]
, max2 ([ 1, 1000, 100, 101, 109, 99 ])
// [ { val: 1000, i: 1 }, { val: 109: i 4 } ]
, max2 ([ 9, 9, 9, 9, 9, 2, 2, 2 ])
// [ { val: 9, i: 1 }, { val: 9, i: 0 } ]
)
您问不使用reduce
会是什么样。我们做到这一点的一种方法是使用helper
函数,并使用更新的参数递归调用它。当我们遇到基本情况时,我们将停止递归调用-
const None =
Symbol ('None')
const max2 = ([ a = None, b = None, ...rest ]) =>
// if a or b are non-values ...
a === None || b === None
? None // return the empty result
// when b is smaller than a
: b < a
? helper // call our helper
( { val: a, i: 0 } // m1 is the larger value (a) with index 0
, { val: b, i: 1 } // m2 is the smaller value (b) with index 1
, 2 // start the next index at 2
, rest // the remaining values of the input list
)
// otherwise, b is larger than a
: helper // call our helper
( { val: b, i: 1 } // m1 is the larger value (b) at index 1
, { val: a, i: 0 } // m2 is the smaller value (a) at index 0
, 2 // start the next index at 2
, rest // the remaining values of the input list
)
const helper = (m1, m2, i, [ val = None, ...rest ]) =>
// base case
val === None
? [ m1, m2 ]
// val is greater than m1
: val > m1.val
? helper // recur ...
( { val, i } // replace m1 with new largest value (val)
, m1 // replace m2 with previous largest value (m1)
, i + 1 // increment index
, rest // with the rest of the list
)
// val is greater than m2
: val > m2.val
? helper // recur ...
( m1 // keep the previous largest value (m1)
, { val, i } // replace m2 with new second largest value (val)
, i + 1 // increment index
, rest // with the rest of the list
)
// otherwise
: helper // recur ...
( m1 // keep the largest value (m1)
, m2 // keep the second largest value (m2)
, i + 1 // increment index
, rest // with the rest of the list
)
console .log
( max2 ([])
// None
, max2 ([ 1 ])
// None
, max2 ([ 24, 64, 3, 54, 2, 80, 20 ])
// [ { val: 80, i: 5 }, { val: 64, i: 1 } ]
, max2 ([ 1, 1000, 100, 101, 109, 99 ])
// [ { val: 1000, i: 1 }, { val: 109: i 4 } ]
, max2 ([ 9, 9, 9, 9, 9, 2, 2, 2 ])
// [ { val: 9, i: 1 }, { val: 9, i: 0 } ]
)
该技术可以推广,因此不需要定义诸如helper
之类的外部函数。而是可以一次性定义通用函数loop
和recur
,然后在希望使用此技术的任何地方调用它。没有隐藏的魔术,只有接受参数并保证结果的函数-
const recur = (...values) =>
({ recur, values })
const loop = f =>
{ let acc =
f ()
while (acc && acc.recur === recur)
acc = f (...acc.values)
return acc
}
const None =
Symbol ('None')
const max2 = ([ a = None, b = None, ...values ]) =>
a === None || b === None
? None
: loop // loop with arguments ...
( ( m1 = { val: a, i: 0 } // init m1 = ...
, m2 = { val: b, i: 1 } // init m2 = ...
, i = 2 // ...
, [ val = None, ...rest ] = values
) =>
// base case
val === None
? [ m1, m2 ] // <- no recur for base case
// m1 must be larger than m2
: m1.val < m2.val
? recur (m2, m1, i, [ val, ...rest ]) // <- retry with swapped m1 and m2
// val > m1
: val > m1.val
? recur ({ val, i }, m1, i + 1, rest) // <- recur
// val > m2
: val > m2.val
? recur (m1, { val, i }, i + 1, rest) // <- recur
// otherwise
: recur (m1, m2, i + 1, rest) // <- recur
)
console .log
( max2 ([])
// None
, max2 ([ 1 ])
// None
, max2 ([ 24, 64, 3, 54, 2, 80, 20 ])
// [ { val: 80, i: 5 }, { val: 64, i: 1 } ]
, max2 ([ 1, 1000, 100, 101, 109, 99 ])
// [ { val: 1000, i: 1 }, { val: 109: i 4 } ]
, max2 ([ 9, 9, 9, 9, 9, 2, 2, 2 ])
// [ { val: 9, i: 1 }, { val: 9, i: 0 } ]
)
上面我们找到了两个(2)最大值,但是我们可以扩展程序以找到最大 N 个值-
console .log
( maxn (3, [])
// None (less than 3 input values)
, maxn (3, [ 1 ])
// None (less than 3 input values)
, maxn (3, [ 24, 64, 3, 54, 2, 80, 20 ])
// [ { val: 80, i: 5 }, { val: 64, i: 1 }, { val: 54, i: 3 } ]
, maxn (3, [ 1, 1000, 100, 101, 109, 99 ])
// [ { val: 1000, i: 1 }, { val: 109, i: 4 }, { val: 101, i: 3 } ]
, maxn (3, [ 9, 9, 9, 9, 9, 2, 2, 2 ])
// [ { val: 9, i: 1 }, { val: 9, i: 2 }, { val: 9, i: 3 } ]
)
以下是使用maxn
和辅助函数reduce
的{{1}}的可能实现-
insert
再说一次,但这一次使用我们不可思议的const maxn = (n = 1, values = []) =>
n >= values.length
? None
: values .reduce
( (acc, val, i) =>
insert ({ val, i }, acc)
, []
)
.slice (0, n)
const insert = (a, [ b = None, ...rest ]) =>
b == None
? [ a ]
: a.val > b.val
? [ a, b, ...rest ]
: [ b, ...insert (a, rest) ]
和loop
-
recur
展开下面的代码片段,以阅读其他源注释并在您自己的浏览器中验证结果-
const maxn = (n = 1, values = []) =>
n >= values.length
? None
: loop
( ( acc = []
, i = 0
) =>
i >= values.length
? n > acc.length
? None
: acc .slice (0, n)
: recur
( insert
({ val: values[i], i }
, acc
)
, i + 1
)
)
const insert = (a, values = []) =>
loop
( ( acc = []
, [ b = None, ...rest ] = values
) =>
b === None
? [ ...acc, a ]
: a.val > b.val
? [ ...acc, b, ...rest ]
: recur
( [ ...acc, b ]
, rest
)
)