简体   繁体   English

Javascript - 根据另一个数组对数组进行排序

[英]Javascript - sort array based on another array

Is it possible to sort and rearrange an array that looks like this:是否可以对如下所示的数组进行排序和重新排列:

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

to match the arrangement of this array:匹配这个数组的排列:

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

Unfortunately, I don't have any IDs to keep track on.不幸的是,我没有任何 ID 可以跟踪。 I would need to priority the items-array to match the sortingArr as close as possible.我需要优先考虑项目数组以尽可能接近地匹配 sortingArr。

Update:更新:

Here is the output I'm looking for:这是我要找的 output:

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

Any idea how this can be done?知道如何做到这一点吗?

One-Line answer.单行答案。

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

Or even shorter:甚至更短:

itemsArray.sort((a, b) => sortingArr.indexOf(a) - sortingArr.indexOf(b));

Something like:就像是:

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
})

Here's a shorter code, but it destroys the sorting array:这是一个较短的代码,但它破坏了sorting数组:

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

If you use the native array sort function, you can pass in a custom comparator to be used when sorting the array.如果您使用原生数组排序功能,您可以传入自定义比较器以在对数组进行排序时使用。 The comparator should return a negative number if the first value is less than the second, zero if they're equal, and a positive number if the first value is greater.如果第一个值小于第二个,比较器应该返回一个负数,如果它们相等则返回零,如果第一个值更大,则比较器应该返回一个正数。

So if I understand the example you're giving correctly, you could do something like:因此,如果我理解您正确给出的示例,您可以执行以下操作:

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

itemsArray.sort(sortFunc);

Case 1: Original Question (No Libraries)案例 1:原始问题(无库)<\/h2>

Plenty of other answers that work.许多其他有效的答案。 :) :)

Case 2: Original Question (Lodash.js or Underscore.js)案例 2:原始问题(Lodash.js 或 Underscore.js)<\/h2>
 var groups = _.groupBy(itemArray, 1); var result = _.map(sortArray, function (i) { return groups[i].shift(); });<\/code><\/pre>

Case 3: Sort Array1 as if it were Array2案例 3:像 Array2 一样对 Array1 进行排序<\/h2>

I'm guessing that most people came here looking for an equivalent to PHP's array_multisort (I did) so I thought I'd post that answer as well.我猜大多数人来这里是为了寻找与 PHP 的 array_multisort 等效的东西(我做过),所以我想我也会发布这个答案。 There are a couple options:有几个选项:

1. There's an existing JS implementation of array_multisort()<\/a> . 1. array_multisort() 有一个现有的 JS 实现<\/a>。 Thanks to @Adnan for pointing it out in the comments.感谢@Adnan 在评论中指出。 It is pretty large, though.不过,它相当大。

2. Write your own. 2. 自己写。 ( JSFiddle demo<\/a> ) JSFiddle 演示<\/a>)

 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]; }); }<\/code><\/pre>

3. Lodash.js<\/a> or Underscore.js<\/a> (both popular, smaller libraries that focus on performance) offer helper functions that allow you to do this: 3. Lodash.js<\/a>或Underscore.js<\/a> (都是流行的,专注于性能的小型库)提供帮助函数,让您可以这样做:

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

...Which will (1) group the sortArray into [index, value]<\/code> pairs, (2) sort them by the value (you can also provide a callback here), (3) replace each of the pairs with the item from the itemArray at the index the pair originated from. ...这将(1)将 sortArray 分组为[index, value]<\/code>对,(2)按值对它们进行排序(您也可以在此处提供回调),(3)用itemArray 位于该对源自的索引处。

"

this is probably too late but, you could also use some modified version of the code below in ES6 style.这可能为时已晚,但您也可以使用 ES6 风格的以下代码的一些修改版本。 This code is for arrays like:此代码适用于以下数组:

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

Why not something like为什么不喜欢

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

array1 = array2.map((object, i) => array1[object]);

 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);

I would use an intermediary object ( itemsMap ), thus avoiding quadratic complexity:我会使用中间对象( 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;
}

See http://jsfiddle.net/eUskE/http://jsfiddle.net/eUskE/

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;
        }
    }
}

ES6 ES6

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

In case you get here needing to do this with an array of objects, here is an adaptation of @Durgpal Singh's awesome answer:如果您到这里需要对一组对象执行此操作,这里是对@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);
})
let a = ['A', 'B', 'C' ]

let b = [3, 2, 1]

let c = [1.0, 5.0, 2.0]

// these array can be sorted by sorting order of b

const zip = rows => rows[0].map((_, c) => rows.map(row => row[c]))

const sortBy = (a, b, c) => {
  const zippedArray = zip([a, b, c])
  const sortedZipped = zippedArray.sort((x, y) => x[1] - y[1])

  return zip(sortedZipped)
}

sortBy(a, b, c)

This is what I was looking for and I did for sorting an Array of Arrays based on another Array:这就是我一直在寻找的东西,并且我根据另一个数组对数组数组进行排序:

It's On^3 and might not be the best practice(ES6)它是 On^3 并且可能不是最佳实践(ES6)

<\/blockquote>

 function sortArray(arr, arr1){ return arr.map(item => { let a = []; for(let i=0; i< arr1.length; i++){ for (const el of item) { if(el == arr1[i]){ a.push(el); } } } return a; }); } const arr1 = ['fname', 'city', 'name']; const arr = [['fname', 'city', 'name'], ['fname', 'city', 'name', 'name', 'city','fname']]; console.log(sortArray(arr,arr1));<\/code><\/pre>
It might help someone它可能会帮助某人

"

I had to do this for a JSON payload I receive from an API, but it wasn't in the order I wanted it.我必须为从 API 收到的 JSON 有效负载执行此操作,但它不是我想要的顺序。

Array to be the reference array, the one you want the second array sorted by:数组作为参考数组,您希望第二个数组按以下方式排序:

var columns = [
    {last_name: "last_name"},
    {first_name: "first_name"},
    {book_description: "book_description"},
    {book_id: "book_id"},
    {book_number: "book_number"},
    {due_date: "due_date"},
    {loaned_out: "loaned_out"}
];

For getting a new ordered array, you could take a Map and collect all items with the wanted key in an array and map the wanted ordered keys by taking sifted element of the wanted group.为了获得一个新的有序数组,您可以使用一个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);

let sortedOrder = [ 'b', 'c', 'b', 'b' ]
let itemsArray = [ 
    ['Anne', 'a'],
    ['Bob', 'b'],
    ['Henry', 'b'],
    ['Andrew', 'd'],
    ['Jason', 'c'],
    ['Thomas', 'b']
]
a.itemsArray(function (a, b) {
    let A = a[1]
    let B = b[1]

    if(A != undefined)
        A = A.toLowerCase()

    if(B != undefined)
        B = B.toLowerCase()

    let indA = sortedOrder.indexOf(A)
    let indB = sortedOrder.indexOf(B)

    if (indA == -1 )
        indA = sortedOrder.length-1
    if( indB == -1)
        indB = sortedOrder.length-1

    if (indA < indB ) {
        return -1;
    } else if (indA > indB) {
        return 1;
    }
    return 0;
})

I hope that I am helping someone, but if you are trying to sort an array of objects by another array on the first array's key, for example, you want to sort this array of objects:我希望我能帮到别人,但是如果你试图通过第一个数组的键上的另一个数组对一个对象数组进行排序,例如,你想要对这个对象数组进行排序:

const foo = [
  {name: 'currency-question', key: 'value'},
  {name: 'phone-question', key: 'value'},
  {name: 'date-question', key: 'value'},
  {name: 'text-question', key: 'value'}
];        

by this array:通过这个数组:

const bar = ['text-question', 'phone-question', 'currency-question', 'date-question'];

you can do so by:你可以这样做:

foo.sort((a, b) => bar.indexOf(a.name) - bar.indexOf(b.name));
  const result = sortingArr.map((i) => {
    const pos = itemsArray.findIndex(j => j[1] === i);
    const item = itemsArray[pos];
    itemsArray.splice(pos, 1);
    return item;
  });

this should works:这应该有效:

var i,search, itemsArraySorted = [];
while(sortingArr.length) {
    search = sortingArr.shift();
    for(i = 0; i<itemsArray.length; i++) {
        if(itemsArray[i][1] == search) {
            itemsArraySorted.push(itemsArray[i]);
            break;
        }
    } 
}

itemsArray = itemsArraySorted;

You could try this method.你可以试试这个方法。

const sortListByRanking = (rankingList, listToSort) => {
  let result = []

  for (let id of rankingList) {
    for (let item of listToSort) {
      if (item && item[1] === id) {
        result.push(item)
      }
    }
  }

  return result
}

with numerical sortingArr:使用数字排序Arr:

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

This seems to work for me:这似乎对我有用:

var outputArray=['10','6','8','10','4','6','2','10','4','0','2','10','0'];
var template=['0','2','4','6','8','10'];
var temp=[];

for(i=0;i<template.length;i++) {
  for(x=0;x<outputArray.length;x++){
    if(template[i] == outputArray[x]) temp.push(outputArray[x])
  };
}

outputArray = temp;
alert(outputArray)

Use the $.inArray() method from jQuery.使用 jQuery 中的 $.inArray() 方法。 You then could do something like this然后你可以做这样的事情

var sortingArr = [ 'b', 'c', 'b', 'b', 'c', 'd' ];
var newSortedArray = new Array();

for(var i=sortingArr.length; i--;) {
 var foundIn = $.inArray(sortingArr[i], itemsArray);
 newSortedArray.push(itemsArray[foundIn]);
}

Use intersection of two arrays.使用两个数组的交集。

Ex:前任:

var sortArray = ['a', 'b', 'c',  'd', 'e'];

var arrayToBeSort = ['z', 's', 'b',  'e', 'a'];

_.intersection(sortArray, arrayToBeSort) 

=> ['a', 'b', 'e'] => ['a', 'b', 'e']

if 'z and 's' are out of range of first array, append it at the end of result如果 'z 和 's' 超出第一个数组的范围,则将其附加到结果的末尾

this.arrToBeSorted =  this.arrToBeSorted.sort(function(a, b){  
  return uppthis.sorrtingByArray.findIndex(x => x.Id == a.ByPramaeterSorted) - uppthis.sorrtingByArray.findIndex(x => x.Id == b.ByPramaeterSorted);
});

You can do something like this:你可以这样做:

function getSorted(itemsArray , sortingArr ) {
  var result = [];
  for(var i=0; i<arr.length; i++) {
    result[i] = arr[sortArr[i]];
  }
  return result;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM