Javascript:对长度为N的数组进行排序并获得最高m

时间:2018-04-29 13:58:18

标签: javascript arrays algorithm

我的长度超过200,000。我需要获得前10名的价值。我知道排序不是最好的解决方案。我尝试了以下解决方案:

const sortBy = 'key';
const results = [];
const m = 10;
const N = array.length;

while (array.length && results.length < m) {
    let currentMax = 0;
    let currentMaxIndex = 0;
    array.forEach((record, i) => {
        if (record[sortBy] >= currentMax) {
            currentMax = record[sortBy];
            currentMaxIndex = i;
        }
    });
    results.push(...array.splice(currentMaxIndex, 1));
}

此处数组是长度为200,000的Array

  

问题是,我认为如果m等于N,那么这就是   比sort本身需要更多的时间。我想知道是否有   是一个更好的解决方案,可以处理这两种情况。

感谢您的帮助,但实际问题是m ∈ (0, N)m可以使用N之前的任何值。那么,在哪一点上建议切换到内置的sort

根据我的理解,当m到达N时,复杂度会增加,排序是m === N

时的最佳解决方案

我已经使用@ t-j-crowder here提供的示例进行了测试。从100个条目中获得前10名的测试。

m中使用不同的值进行测试时,更快的算法会在sort更改为m === 85。所以,我想知道是否有办法确定何时应该切换回排序,以便在所有情况下都能获得最佳性能。

2 个答案:

答案 0 :(得分:2)

您不需要对整个数组进行排序,只需按数字顺序插入前10个数组并删除任何其他条目:

&#13;
&#13;
var a = Array.from({length:100}, () => Math.floor(Math.random() * 1000000));

var check = a.slice().sort((left, right) => right - left).slice(0, 10);
console.log("check", check);

function checkResult(top10) {
    var n;
    for (n = 0; n < 10; ++n) {
        if (top10[n] !== check[n]) {
            console.log("Error in test at #" + n + ", expected " + check[n] + ", got " + top10[n]);
            return false;
        }
    }
    return true;
}

var top10 = [];
var cutoff = -Infinity;
var full = false;
var n, len, value;
for (n = 0, len = a.length; n < len; ++n) {
  value = a[n];
  // If the value may be in the top 10...
  if (!full || value >= cutoff) {
    // Insert into top10
    let found = false;
    for (let n = 0; n < top10.length; ++n) {
      if (top10[n] <= value) {
        top10.splice(n, 0, value);
        found = true;
        break;
      }
    }
    if (!found) {
      top10.push(value);
    }
    // Trim it
    if (top10.length > 10) {
      full = true;
      top10.length = 10;
    }
    // Remember the lowest of the top 10 candidates we have now so we can not bother with checking lower ones
    cutoff = top10[top10.length - 1];
  }
}

console.log("top10", top10);
console.log("Good? " + checkResult(top10));
&#13;
.as-console-wrapper {
  max-height: 100% !important;
}
&#13;
&#13;
&#13;

你可以稍微整理一下,进一步优化它,但你明白了。维护一份仅列出前10名的最高名单,如果其他人加入,则将其从最底层删除。

Benchmark here,轻松击败排名,然后抢占Chrome和Firefox的前10名;相反,在Edge上也是如此。

答案 1 :(得分:0)

  function limitSort(array, sortBy, limit) {
    const result = [];
    // Iterate over the array *once*
    for(const el of array) {
      // Exclude all elements that are definetly not in the resulting array
      if(result.length < limit || el[sortBy] > result[0]) {
        // Determine the position were the element needs to be inserted (Insertion sort)
        let insertAt = 0;
        while(insertAt < result.length && result[insertAt][sortBy] < el[sortBy]) insertAt++;
        // Finally insert it
        result.splice(insertAt, 0, el);
        // If the results are getting to long, remove the lowest element
        if(result.length > limit)
          result.splice(0, 1);
      }
    }
    return result;
 }

这实现了上面提出的算法Niet the Dark AbsolTry it!