Javascript - 基于另一个数组排序数组

use*_*892 131 javascript

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

itemsArray = [ 
    ['Anne', 'a'],
    ['Bob', 'b'],
    ['Henry', 'b'],
    ['Andrew', 'd'],
    ['Jason', 'c'],
    ['Thomas', 'b']
]
Run Code Online (Sandbox Code Playgroud)

匹配此数组的排列:

sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ]
Run Code Online (Sandbox Code Playgroud)

不幸的是,我没有任何ID可以跟踪.我需要优先使items-array与sortedArr匹配尽可能接近.

更新:

这是我正在寻找的输出:

itemsArray = [    
    ['Bob', 'b'],
    ['Jason', 'c'],
    ['Henry', 'b'],
    ['Thomas', 'b']
    ['Anne', 'a'],
    ['Andrew', 'd'],
]
Run Code Online (Sandbox Code Playgroud)

知道如何做到这一点?

Dur*_*ngh 165

一线答案.

itemsArray.sort(function(a, b){  
  return sortingArr.indexOf(a) - sortingArr.indexOf(b);
});
Run Code Online (Sandbox Code Playgroud)

  • @Morvael,这是因为这个答案要求 `sortingArr` 包含 `itemsArray` 中的所有值。解决方法是,如果 `sortingArr` 中不存在项目,则将其推到数组的后面: ```allProducts.sort((product1, Product2) => { const index1 = manualSort.indexOf(product1.id); const index2 = manualSort.indexOf(product2.id); return ( (index1 > -1 ? index1 : Infinity) - (index2 > -1 ? index2 : Infinity) ); });``` (11认同)
  • 这将改变`itemsArray`.根据性能要求,`itemsArray.slice().sort(...)`会更安全. (9认同)
  • 它的确返回数组,但它也进行适当的排序并变异原始数组。 (7认同)
  • sort 方法返回一个数组。请参阅 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort (2认同)
  • 这应该是真正的答案 (2认同)
  • 有人可以解释一下为什么/这是如何工作的吗?我已经尝试使用类似于 OP 的数据、其中一个成员是 GUID 的对象数组以及这些 GUID 的排序数组。在尝试之前我很怀疑,并发现..正如我预期的那样,这对订单没有影响。 (2认同)

geo*_*org 66

就像是:

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
})
Run Code Online (Sandbox Code Playgroud)

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

result = items.map(function(item) {
    var n = sorting.indexOf(item[1]);
    sorting[n] = '';
    return [n, item]
}).sort().map(function(j) { return j[1] })
Run Code Online (Sandbox Code Playgroud)

  • 二次复杂度!尝试使用大量数据...... (16认同)
  • @ thg435:复杂性与"优化"几乎没有关系,除非保证数据量很小(这可能就是这种情况). (5认同)
  • @georg 当谈到作用于数据结构的算法的复杂性时,对具有二次(或更差)复杂性的算法进行优化永远不会过早,而且总是必要的(除非您可以保证数据集的大小会很小) . 性能上的差异(从字面上看)以数量级表示。 (4认同)

小智 32

如果使用本机数组排序功能,则可以传入自定义比较器以在排序数组时使用.如果第一个值小于第二个值,比较器应返回负数,如果它们相等则返回零,如果第一个值更大,则返回正数.

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

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

itemsArray.sort(sortFunc);
Run Code Online (Sandbox Code Playgroud)

  • 如果`sortingArr`中的"ids"是唯一的,我更喜欢这个答案 - 幸运的是,它们在我的情况下:) (5认同)
  • 您应该在函数外部声明 sortingArray 以避免在每次排序迭代时重新声明它 (4认同)
  • 那是行不通的,由于indexOf返回第一个索引,因此生成的顺序为b,b,b,c,c,d。 (3认同)

Don*_*rdy 26

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

许多其他有效的答案.:)

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

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

情况3:将Array1排序为Array2

我猜大多数人来到这里寻找相当于PHP的array_multisort(我做过),所以我想我也会发布这个答案.有几种选择:

1.有一个array_multisort()的现有JS实现.感谢@Adnan在评论中指出它.但它非常大.

写自己的.(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];
  });
}
Run Code Online (Sandbox Code Playgroud)

3. Lodash.jsUnderscore.js提供的辅助功能,让你这样做(即注重性能既叫好,小库):

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

...其中(1)将sortArray分组[index, value]成对,(2)按值排序(这里也可以提供回调),(3)用索引中itemArray中的项替换每个对一对起源于.


Sus*_*uth 19

这可能为时已晚,但您也可以在ES6风格中使用下面代码的某些修改版本.此代码适用于以下数组:

var arrayToBeSorted = [1,2,3,4,5];
var arrayWithReferenceOrder = [3,5,8,9];
Run Code Online (Sandbox Code Playgroud)

实际操作:

arrayToBeSorted = arrayWithReferenceOrder.filter(v => arrayToBeSorted.includes(v));
Run Code Online (Sandbox Code Playgroud)

ES5中的实际操作:

arrayToBeSorted = arrayWithReferenceOrder.filter(function(v) {
    return arrayToBeSorted.includes(v);
});
Run Code Online (Sandbox Code Playgroud)

应该导致 arrayToBeSorted = [3,5]

不破坏引用数组.

  • 如果我的arrayToBeSorted是一个对象数组,即:{1:{...},2:{...},3:{...},4:{...},5:{...}},该怎么办?但是arrayWithReferenceOrder只是一个普通的数组? (3认同)
  • @sushruth如何对数组进行排序? (3认同)

Luc*_*llo 13

为什么不像

//array1: array of elements to be sorted
//array2: array with the indexes

array1 = array2.map((object, i) => array1[object]);
Run Code Online (Sandbox Code Playgroud)

地图功能可能不适用于所有版本 Javascript


小智 10

function sortFunc(a, b) {
  var sortingArr = ["A", "B", "C"];
  return sortingArr.indexOf(a.type) - sortingArr.indexOf(b.type);
}

const itemsArray = [
  {
    type: "A",
  },
  {
    type: "C",
  },
  {
    type: "B",
  },
];
console.log(itemsArray);
itemsArray.sort(sortFunc);
console.log(itemsArray);
Run Code Online (Sandbox Code Playgroud)


use*_*295 9

如果您需要使用一组对象来执行此操作,这里是Durgpal Singh 精彩答案的改编版:

const itemsArray = [
  { name: 'Anne', id: 'a' },
  { name: 'Bob', id: 'b' },
  { name: 'Henry', id: 'b' },
  { name: 'Andrew', id: 'd' },
  { name: 'Jason', id: 'c' },
  { name: 'Thomas', id: 'b' }
]

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

Object.keys(itemsArray).sort((a, b) => {
  return sortingArr.indexOf(itemsArray[a].id) - sortingArr.indexOf(itemsArray[b].id);
})
Run Code Online (Sandbox Code Playgroud)


Jul*_*yer 6

我将使用中间对象(itemsMap),从而避免二次复杂度:

function createItemsMap(itemsArray) { // {"a": ["Anne"], "b": ["Bob", "Henry"], …}
  var itemsMap = {};
  for (var i = 0, item; (item = itemsArray[i]); ++i) {
    (itemsMap[item[1]] || (itemsMap[item[1]] = [])).push(item[0]);
  }
  return itemsMap;
}

function sortByKeys(itemsArray, sortingArr) {
  var itemsMap = createItemsMap(itemsArray), result = [];
  for (var i = 0; i < sortingArr.length; ++i) {
    var key = sortingArr[i];
    result.push([itemsMap[key].shift(), key]);
  }
  return result;
}
Run Code Online (Sandbox Code Playgroud)

参见http://jsfiddle.net/eUskE/


Nin*_*olz 6

为了获取新的有序数组,您可以获取Map并收集数组中具有所需键的所有项目,并通过获取所需组的筛选元素来映射所需的有序键。

var itemsArray = [['Anne', 'a'], ['Bob', 'b'], ['Henry', 'b'], ['Andrew', 'd'], ['Jason', 'c'], ['Thomas', 'b']],
    sortingArr = [ 'b', 'c', 'b', 'b', 'a', 'd' ],
    map = itemsArray.reduce((m, a) => m.set(a[1], (m.get(a[1]) || []).concat([a])), new Map),
    result = sortingArr.map(k => (map.get(k) || []).shift());

console.log(result);
Run Code Online (Sandbox Code Playgroud)


Can*_*Can 6

ES6

const arrayMap = itemsArray.reduce(
  (accumulator, currentValue) => ({
    ...accumulator,
    [currentValue[1]]: currentValue,
  }),
  {}
);
const result = sortingArr.map(key => arrayMap[key]);
Run Code Online (Sandbox Code Playgroud)

更多不同输入数组的例子


Mit*_*ell 5

var sortedArray = [];
for(var i=0; i < sortingArr.length; i++) {
    var found = false;
    for(var j=0; j < itemsArray.length && !found; j++) {
        if(itemsArray[j][1] == sortingArr[i]) {
            sortedArray.push(itemsArray[j]);
            itemsArray.splice(j,1);
            found = true;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

http://jsfiddle.net/s7b2P/

结果顺序:Bob,Jason,Henry,Thomas,Anne,Andrew


Bul*_*zed 5

我希望我能帮助某人,但是如果您尝试通过第一个数组的键上的另一个数组对对象数组进行排序,例如,您想要对此对象数组进行排序:

const foo = [
  {name: 'currency-question', key: 'value'},
  {name: 'phone-question', key: 'value'},
  {name: 'date-question', key: 'value'},
  {name: 'text-question', key: 'value'}
];        
Run Code Online (Sandbox Code Playgroud)

通过这个数组:

const bar = ['text-question', 'phone-question', 'currency-question', 'date-question'];
Run Code Online (Sandbox Code Playgroud)

您可以通过以下方式执行此操作:

foo.sort((a, b) => bar.indexOf(a.name) - bar.indexOf(b.name));
Run Code Online (Sandbox Code Playgroud)