如何在打字稿中获取2个最大数字数组

时间:2019-01-12 02:36:00

标签: arrays typescript sorting max

我正在尝试从下一个数组中找到2个最大数字的索引和值:

{24,64,3,54,2,80,20}

我不能使用sort方法,因为我需要保留项目的索引。

在此示例中,结果应该是。

max1 = 80
max2 = 64
indexMax1 = 5
indexMax2 = 1

任何帮助将不胜感激。

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之类的外部函数。而是可以一次性定义通用函数looprecur,然后在希望使用此技术的任何地方调用它。没有隐藏的魔术,只有接受参数并保证结果的函数-

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
            )
    )