Javascript - 基于另一个数组对数组进行排序

IT技术 javascript
2021-01-25 07:52:31

是否可以对如下所示的数组进行排序和重新排列:

itemsArray = [ 
    ['Anne', 'a'],
    ['Bob', 'b'],
    ['Henry', 'b'],
    ['Andrew', 'd'],
    ['Jason', 'c'],
    ['Thomas', 'b']
]

匹配这个数组的排列:

sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ]

不幸的是,我没有任何 ID 可以跟踪。我需要优先考虑 items-array 以尽可能匹配 sortingArr。

更新:

这是我正在寻找的输出:

itemsArray = [    
    ['Bob', 'b'],
    ['Jason', 'c'],
    ['Henry', 'b'],
    ['Thomas', 'b']
    ['Anne', 'a'],
    ['Andrew', 'd'],
]

知道如何做到这一点吗?

6个回答

单线回答。

itemsArray.sort(function(a, b){  
  return sortingArr.indexOf(a) - sortingArr.indexOf(b);
});

或者更短:

itemsArray.sort((a, b) => sortingArr.indexOf(a) - sortingArr.indexOf(b));
2021-03-15 07:52:31
它确实返回数组,但它也进行原地排序并改变原始数组。
2021-03-19 07:52:31
这将发生变异itemsArray根据性能要求,这样做会安全得多itemsArray.slice().sort(...)
2021-03-22 07:52:31
这应该是真正的答案
2021-04-06 07:52:31
@Morvael,这是由于此答案要求sortingArr包含itemsArray. 解决方法是将项目推到数组的后面,如果它们不存在于sortingArrallProducts.sort((product1, product2) => { const index1 = manualSort.indexOf(product1.id); const index2 = manualSort.indexOf(product2.id); return ( (index1 > -1 ? index1 : Infinity) - (index2 > -1 ? index2 : Infinity) ); });
2021-04-06 07:52:31

就像是:

items = [ 
    ['Anne', 'a'],
    ['Bob', 'b'],
    ['Henry', 'b'],
    ['Andrew', 'd'],
    ['Jason', 'c'],
    ['Thomas', 'b']
]

sorting = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
result = []

sorting.forEach(function(key) {
    var found = false;
    items = items.filter(function(item) {
        if(!found && item[1] == key) {
            result.push(item);
            found = true;
            return false;
        } else 
            return true;
    })
})

result.forEach(function(item) {
    document.writeln(item[0]) /// Bob Jason Henry Thomas Andrew
})

这是一个较短的代码,但它会破坏sorting数组:

result = items.map(function(item) {
    var n = sorting.indexOf(item[1]);
    sorting[n] = '';
    return [n, item]
}).sort().map(function(j) { return j[1] })
二次复杂度!用大量数据尝试一下……
2021-03-12 07:52:31
@georg 当谈到作用于数据结构的算法的复杂性时,对具有二次(或更差)复杂性的算法进行优化永远不会过早,而且总是必要的(除非您可以保证数据集的大小会很小) . 性能上的差异(从字面上看)以数量级表示。
2021-03-16 07:52:31
@thg435:复杂性与“优化”几乎没有关系,除非保证数据量很小(这里可能就是这种情况)。
2021-03-31 07:52:31

如果使用原生数组排序函数,则可以传入自定义比较器,以便在对数组进行排序时使用。如果第一个值小于第二个值,比较器应该返回一个负数,如果它们相等则返回零,如果第一个值更大则返回一个正数。

因此,如果我理解您正确给出的示例,您可以执行以下操作:

function sortFunc(a, b) {
  var sortingArr = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
  return sortingArr.indexOf(a[1]) - sortingArr.indexOf(b[1]);
}

itemsArray.sort(sortFunc);
这不起作用,结果顺序将是 b,b,b,c,c,d 作为indexOf返回第一个索引。
2021-03-25 07:52:31
谢谢,但我希望 itemsArray 的输出与 sortingArray 相匹配。
2021-03-26 07:52:31
如果 中的“id”sortingArr是唯一的,我更喜欢这个答案- 谢天谢地,在我的情况下:)
2021-04-03 07:52:31
您应该声明sortingArray函数外部以避免在每次排序迭代时重新声明它
2021-04-06 07:52:31

案例 1:原始问题(无库)

很多其他有效的答案。:)

案例 2:原始问题(Lodash.js 或 Underscore.js)

var groups = _.groupBy(itemArray, 1);
var result = _.map(sortArray, function (i) { return groups[i].shift(); });

案例 3:将 Array1 排序为 Array2

我猜大多数人来这里是为了寻找与 PHP 的 array_multisort 等效的(我这样做了),所以我想我也会发布该答案。有几个选项:

1. 有一个array_multisort()的现有JS 实现感谢@Adnan 在评论中指出。不过,它相当大。

2. 自己写。( JSFiddle 演示)

function refSort (targetData, refData) {
  // Create an array of indices [0, 1, 2, ...N].
  var indices = Object.keys(refData);

  // Sort array of indices according to the reference data.
  indices.sort(function(indexA, indexB) {
    if (refData[indexA] < refData[indexB]) {
      return -1;
    } else if (refData[indexA] > refData[indexB]) {
      return 1;
    }
    return 0;
  });

  // Map array of indices to corresponding values of the target array.
  return indices.map(function(index) {
    return targetData[index];
  });
}

3. Lodash.jsUnderscore.js(既叫好,小库,集中表现)提供的辅助功能,让你这样做:

    var result = _.chain(sortArray)
      .pairs()
      .sortBy(1)
      .map(function (i) { return itemArray[i[0]]; })
      .value();

...这将 (1) 将 sortArray 分组为[index, value]对,(2) 按值对它们进行排序(您也可以在此处提供回调),(3) 将每个对替换为 itemArray 索引处的项目对起源于。

优秀的解决方案,或者如果您的数据结构有点复杂,您可以使用 _.indexBy 并删除移位
2021-03-15 07:52:31

这可能为时已晚,但您也可以使用以下 ES6 样式代码的一些修改版本。此代码适用于如下数组:

var arrayToBeSorted = [1,2,3,4,5];
var arrayWithReferenceOrder = [3,5,8,9];

实际操作:

arrayToBeSorted = arrayWithReferenceOrder.filter(v => arrayToBeSorted.includes(v));

ES5中的实际操作:

arrayToBeSorted = arrayWithReferenceOrder.filter(function(v) {
    return arrayToBeSorted.includes(v);
});

应该导致 arrayToBeSorted = [3,5]

不破坏引用数组。

@Crystal,那是一个对象,而不是一个对象数组。对象中的元素/项目没有顺序,即它们的顺序没有设置。一组对象看起来像[{name: "1"}, {name: "2"}, {name: "3"}, ...].
2021-03-15 07:52:31
@sushruth 这是如何对数组进行排序的?
2021-03-20 07:52:31
如果我的arrayToBeSorted 是一个对象数组,即:{1: {…}, 2: {…}, 3: {…}, 4: {…}, 5: {…}} 怎么办?但是 arrayWithReferenceOrder 只是一个普通的数组?
2021-03-22 07:52:31