导出最高10个值的子集数组的最简单方法?

时间:2009-01-27 13:41:10

标签: javascript

在javascript中我有一个数组如下:

var foo = [2, 2, 4, 4, 128, 2, 2, 1, 4, 18, 27, 16, 2, 1, 18, 21, 5, 1, 128, 1, 2, 2, 1, 18, 12, 60, 2, 28, 1, 17, 2, 3, 4, 2, 2, 2, 1, 27, 2, 17, 7, 2, 2, 2, 5, 1, 2, 4, 7, 1, 2, 1, 1, 1, 2, 1, 5, 7, 2, 7, 6, 1, 7, 1, 5, 8, 4];

我感兴趣的是找到一种方法(在一个循环中,而不是多个)来导出最高10个值的子集数组,其中值的前一个位置是'key'(因此模拟Map对象):

例如:

var fooTopTen = [[4, 128], [18, 128], [25, 60], [27, 28], [10, 27], [37, 27], [15, 21], [9, 18], [14, 18], [23, 18]];

6 个答案:

答案 0 :(得分:2)

我之前的回答使用了反向索引表,但包含了一些错误 - 现在已经修复了 - 并且比以下代码更难理解。

这实际上是答案中给出的所有解决方案中最慢的 - 为了获得最佳性能,请查看我的其他答案。

var foo = [2, 2, 4, 4, 128, 2, 2, 1, 4, 18, 27, 16, 2, 1, 18, 21, 5, 1, 128, 1, 2, 2, 1, 18, 12, 60, 2, 28, 1, 17, 2, 3, 4, 2, 2, 2, 1, 27, 2, 17, 7, 2, 2, 2, 5, 1, 2, 4, 7, 1, 2, 1, 1, 1, 2, 1, 5, 7, 2, 7, 6, 1, 7, 1, 5, 8, 4];

var fooTopTen = [];

// add index to values
for(var i = 0, len = foo.length; i < len; ++i)
    fooTopTen.push([i, foo[i]]);

// sort first by value (descending order), then by index (ascending order)
fooTopTen.sort(function(t1, t2) {
    return t2[1] - t1[1] || t1[0] - t2[0];
});

// shorten array to correct size
fooTopTen.length = 10;

// output top ten to check result
document.writeln('[[' + fooTopTen.join('], [') + ']]');

比较函数的第二部分(比较索引的部分)不需要,因为sort()在大多数实现中都是稳定的(ECMA according to MDC不需要这样做)。我将把它作为一个例子来说明如何进行多种要求的排序......

答案 1 :(得分:1)

这是使用索引表的前一个答案的详细版本。我做了一点基准测试,对于问题中给出的输入,这个解决方案将比此线程中建议的任何其他内容更快:

var foo = [2, 2, 4, 4, 128, 2, 2, 1, 4, 18, 27, 16, 2, 1, 18, 21, 5, 1, 128, 1, 2, 2, 1, 18, 12, 60, 2, 28, 1, 17, 2, 3, 4, 2, 2, 2, 1, 27, 2, 17, 7, 2, 2, 2, 5, 1, 2, 4, 7, 1, 2, 1, 1, 1, 2, 1, 5, 7, 2, 7, 6, 1, 7, 1, 5, 8, 4];

var indexTable = {}, uniqueValues = [];

// --- build reverse index table, find unique values

for(var i = foo.length; i--; ) {
    var value = foo[i];
    if(indexTable.hasOwnProperty(value))
        indexTable[value].push(i);
    else {
        indexTable[value] = [i];
        uniqueValues.push(value);
    }
}

// --- sort unique values in ascending order

uniqueValues.sort(function(i1, i2) {
    return i1 - i2;
});

// --- find ten greatest values

var fooTopTen = [], k = 0;

for(var i = uniqueValues.length; k < 10 && i--; ) {
    var value = uniqueValues[i],
        indices = indexTable[value];

    for(var j = indices.length; k < 10 && j--; )
        fooTopTen[k++] = [indices[j], value];
}

// --- output result

document.writeln('[[' + fooTopTen.join('], [') + ']]');

答案 2 :(得分:1)

它在搜索的主数组中运行一次,在结果数组中的适当位置插入项目:

function top10(arr) {
  var results = [[0,Number.MAX_VALUE],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]];

  for (var i=0; i<arr.length; i++) {
    // search from back to front
    for (var j=9; j>=0; j--) {
       if (arr[i] <= results[j][1]) {
         if (j==9)
           break;
         results.splice(j+1, 0, [i, arr[i]]);
         results.pop();
         break;
      }
    }
  }
  return results.slice(1);
}

对于大型数组,这甚至应该相当快,因为​​大多数情况下内部循环应该只进行一次迭代。

答案 3 :(得分:0)

var foo = [2, 2, 4, 4, 128, 2, 2, 1, 4, 18, 27, 16, 2, 1, 18, 21, 5, 1, 128, 1, 2, 2, 1, 18, 12, 60, 2, 28, 1, 17, 2, 3, 4, 2, 2, 2, 1, 27, 2, 17, 7, 2, 2, 2, 5, 1, 2, 4, 7, 1, 2, 1, 1, 1, 2, 1, 5, 7, 2, 7, 6, 1, 7, 1, 5, 8, 4];

var index = 0;
var result = foo.map( function(a){ return [index++, a]; } )
         .sort( function(a,b){ return (a[1] < b[1]); } )
         .splice( 0, 10 );

document.write(result.join( '  ' ));

如果foo与所需结果的大小相比非常大,则可能会更快地迭代foo插入 - 在我们遇到它时将每个元素排序到结果中。

答案 4 :(得分:0)

// Sorting method
function sortNumber(a, b) {
    return a - b;
}

// Find the offset of an element in array
function findOffset(element, array) {
    for (var i = 0; i < array.length; i++) {
        if (array[i] == element) {
            // Make sure we don't find it again
            array[i] = null;
            return i;
        }
    }
}

var foo = [2, 2, 4, 4, 128, 2, 2, 1, 4, 18, 27, 16, 2, 1, 18, 21, 5, 1, 128, 1, 2, 2, 1, 18, 12, 60, 2, 28, 1, 17, 2, 3, 4, 2, 2, 2, 1, 27, 2, 17, 7, 2, 2, 2, 5, 1, 2, 4, 7, 1, 2, 1, 1, 1, 2, 1, 5, 7, 2, 7, 6, 1, 7, 1, 5, 8, 4];
// Copies
var bar = foo.slice();
var baz = foo.slice();
var fooTopTen = new Array(10);
// Sort
bar.sort(sortNumber).reverse();
// Create the results
for (var i = 0; i < 10; i++) {
    fooTopTen[i] = new Array(2);
    fooTopTen[i][0] = findOffset(bar[i], baz);
    fooTopTen[i][1] = bar[i];
}

答案 5 :(得分:0)

计算机科学与答案:

问题陈述:给定长度为N的大数组X,以及小数m <1。 N(此处m = 10),产生长度为m的数组Y,其中Y的每个元素包含对{i,X [i]},使得X {i}的集合是X的m个最大元素。

如果m远小于N,则循环遍历X的元素并将它们分类为Y,丢弃对以保持最多m个元素。 (即提到的moonshadow)

排序X将花费你O(N log N)元素。迭代X并排序到Y应该只花费O(N log m)元素。