Javascript:对数组进行排序并返回一个索引数组,这些索引指示已排序元素相对于原​​始元素的位置

时间:2010-09-16 20:27:17

标签: javascript indexing sorting

假设我有一个Javascript数组,如下所示:

var test = ['b', 'c', 'd', 'a'];

我想对数组进行排序。显然,我可以这样做来对数组进行排序:

test.sort(); //Now test is ['a', 'b', 'c', 'd']

但我真正想要的是一个索引数组,它指示排序元素相对于原​​始元素的位置。我不太清楚怎么说这个,所以也许这就是为什么我无法弄清楚如何去做。

如果这样的方法被称为sortIndices(),那么我想要的是:

var indices = test.sortIndices();
//At this point, I want indices to be [3, 0, 1, 2].

'a'位于第3位,'b'位于0,'c'位于1且'd'在原始数组中为2。因此,[3,0,1,2]。

一种解决方案是对数组的副本进行排序,然后遍历排序的数组并找到原始数组中每个元素的位置。但是,这感觉很笨拙。

现有方法是否符合我的要求?如果没有,您将如何编写一个执行此操作的方法?

8 个答案:

答案 0 :(得分:40)

var test = ['b', 'c', 'd', 'a'];
var test_with_index = [];
for (var i in test) {
    test_with_index.push([test[i], i]);
}
test_with_index.sort(function(left, right) {
  return left[0] < right[0] ? -1 : 1;
});
var indexes = [];
test = [];
for (var j in test_with_index) {
    test.push(test_with_index[j][0]);
    indexes.push(test_with_index[j][1]);
}

修改

你们对for .. in是正确的。如果有人打开阵列原型,那将会破坏,我经常烦恼地观察。这是固定的,并且包含在一个更有用的功能中。

function sortWithIndeces(toSort) {
  for (var i = 0; i < toSort.length; i++) {
    toSort[i] = [toSort[i], i];
  }
  toSort.sort(function(left, right) {
    return left[0] < right[0] ? -1 : 1;
  });
  toSort.sortIndices = [];
  for (var j = 0; j < toSort.length; j++) {
    toSort.sortIndices.push(toSort[j][1]);
    toSort[j] = toSort[j][0];
  }
  return toSort;
}

var test = ['b', 'c', 'd', 'a'];
sortWithIndeces(test);
alert(test.sortIndices.join(","));

答案 1 :(得分:21)

我只需用数字0..n-1填充一个数组,然后使用比较函数对其进行排序。

var test = ['b', 'c', 'd', 'a'];
var len = test.length;
var indices = new Array(len);
for (var i = 0; i < len; ++i) indices[i] = i;
indices.sort(function (a, b) { return test[a] < test[b] ? -1 : test[a] > test[b] ? 1 : 0; });
console.log(indices);

答案 2 :(得分:6)

Dave Aaron Smith是正确的,不过我觉得在这里使用Array map()很有意思。

var test = ['b', 'c', 'd', 'a'];
// make list with indices and values
indexedTest = test.map(function(e,i){return {ind: i, val: e}});
// sort index/value couples, based on values
indexedTest.sort(function(x, y){return x.val > y.val ? 1 : x.val == y.val ? 0 : -1});
// make list keeping only indices
indices = indexedTest.map(function(e){return e.ind});

答案 3 :(得分:2)

Array.prototype.sortIndices = function (func) {
    var i = j = this.length,
        that = this;

    while (i--) {
        this[i] = { k: i, v: this[i] };
    }

    this.sort(function (a, b) {
        return func ? func.call(that, a.v, b.v) : 
                      a.v < b.v ? -1 : a.v > b.v ? 1 : 0;
    });

    while (j--) {
        this[j] = this[j].k;
    }
}

YMMV关于如何向Array原型添加函数和内联变异数组的感觉,但这允许对可以比较的任何对象的数组进行排序。它需要一个可用于排序的可选功能,就像Array.prototype.sort

一样

一个例子,

var test = [{b:2},{b:3},{b:4},{b:1}];

test.sortIndices(function(a,b) { return a.b - b.b; });

console.log(test); // returns [3,0,1,2]

答案 4 :(得分:2)

您可以使用es6(生成0->N-1索引数组并根据输入值对其进行排序)使用单行完成此操作。

var test = ['b', 'c', 'd', 'a']

var result = Array.from(Array(test.length).keys())
                  .sort((a, b) => test[a] < test[b] ? -1 : (test[b] < test[a]) | 0)

答案 5 :(得分:1)

这是clerbois回答的一个更惯用的ES6版本,请参见他/她的评论:

return test.map((val, ind) => {return {ind, val}})
           .sort((a, b) => {return a.val > b.val ? 1 : a.val == b.val ? 0 : -1 })
           .map((obj) => obj.ind);

答案 6 :(得分:0)

您可以使用Map对象执行此操作。只需将键/值设置为索引/值,然后使用Array.from将Iterator设为二维数组,然后对索引,值或两者进行排序。

function sorting(elements) {
  const myMap = new Map();
  elements.forEach((value, index) => {
    myMap.set(index, value);
  });
  const arrayWithOrderedIndexes = Array.from(myMap.entries()).sort((left, right) => {return left[1] < right[1] ? -1 : 1});
  myMap.clear();
  return arrayWithOrderedIndexes.map(elem => elem[0]);
}
const elements = ['value','some value','a value','zikas value','another value','something value','xtra value'];
sorting(elements);

答案 7 :(得分:-1)

您可以做到这一点!


detailItems.slice()
   .map((r, ix) => {
       r._ix = ix;
       return r;
   })
   .sort((a,b) => {
      ... /* you have a._ix or b._ix here !! */
   })

.slice()克隆您的数组以防止产生副作用:))