Javascript 以相同的方式对两个数组进行排序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11499268/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 06:03:38  来源:igfitidea点击:

Sort two arrays the same way

javascript

提问by supercoolville

For example, if I have these arrays:

例如,如果我有这些数组:

var name = ["Bob","Tom","Larry"];
var age =  ["10", "20", "30"];

And I use name.sort()the order of the "name" array becomes:

我使用name.sort()“名称”数组的顺序变为:

var name = ["Bob","Larry","Tom"];

But, how can I sort the "name" array and have the "age" array keep the same order? Like this:

但是,如何对“name”数组进行排序并使“age”数组保持相同的顺序?像这样:

var name = ["Bob","Larry","Tom"];
var age =  ["10", "30", "20"];

回答by jwatts1980

You can sort the existing arrays, or reorganize the data.

您可以对现有数组进行排序,或重新组织数据。

Method 1:To use the existing arrays, you can combine, sort, and separate them: (Assuming equal length arrays)

方法一:使用已有的数组,可以对它们进行组合、排序、分离:( 假设数组长度相等)

var names = ["Bob","Tom","Larry"];
var ages =  ["10", "20", "30"];

//1) combine the arrays:
var list = [];
for (var j = 0; j < names.length; j++) 
    list.push({'name': names[j], 'age': ages[j]});

//2) sort:
list.sort(function(a, b) {
    return ((a.name < b.name) ? -1 : ((a.name == b.name) ? 0 : 1));
    //Sort could be modified to, for example, sort on the age 
    // if the name is the same.
});

//3) separate them back out:
for (var k = 0; k < list.length; k++) {
    names[k] = list[k].name;
    ages[k] = list[k].age;
}

This has the advantage of not relying on string parsing techniques, and could be used on any number of arrays that need to be sorted together.

这具有不依赖字符串解析技术的优点,并且可以用于需要一起排序的任意数量的数组。

Method 2:Or you can reorganize the data a bit, and just sort a collection of objects:

方法 2:或者您可以稍微重新组织一下数据,只需对一组对象进行排序:

var list = [
    {name: "Bob", age: 10}, 
    {name: "Tom", age: 20},
    {name: "Larry", age: 30}
    ];

list.sort(function(a, b) {
    return ((a.name < b.name) ? -1 : ((a.name == b.name) ? 0 : 1));
});

for (var i = 0; i<list.length; i++) {
    alert(list[i].name + ", " + list[i].age);
}
?

For the comparisons,-1 means lower index, 0 means equal, and 1 means higher index. And it is worth noting that sort()actually changes the underlying array.

对于比较,-1 表示较低的索引,0 表示相等,1 表示较高的索引。值得注意的是,sort()实际上改变了底层数组。

http://jsfiddle.net/ghBn7/38/

http://jsfiddle.net/ghBn7/38/

回答by w35l3y

It is very similar to jwatts1980's answer (Update 2). Consider reading Sorting with map.

它与jwatts1980's answer (Update 2)非常相似。考虑阅读Sorting with map

name.map(function (v, i) {
    return {
        value1  : v,
        value2  : age[i]
    };
}).sort(function (a, b) {
    return ((a.value1 < b.value1) ? -1 : ((a.value1 == b.value1) ? 0 : 1));
}).forEach(function (v, i) {
    name[i] = v.value1;
    age[i] = v.value2;
});

回答by bryan maclee

I was having the same issue and came up with this incredibly simple solution. First combine the associated ellements into strings in a seperate array then use parseInt in your sort comparison function like this:

我遇到了同样的问题,并提出了这个非常简单的解决方案。首先将相关元素组合成单独数组中的字符串,然后在排序比较函数中使用 parseInt ,如下所示:

<html>
<body>
<div id="outPut"></div>
<script>
var theNums = [13,12,14];
var theStrs = ["a","b","c"];
var theCombine = [];

for (var x in theNums)
{
    theCombine[x] = theNums[x] + "," + theStrs;
}

var theSorted = theAr.sort(function(a,b)
{
    var c = parseInt(a,10);
    var d = parseInt(b,10);
    return c-d;
});
document.getElementById("outPut").innerHTML = theS;
</script>
</body>
</html>

回答by ioreskovic

You are trying to sort 2 independet arrays by only calling sort() on one of them.

您试图通过仅对其中一个调用 sort() 来对 2 个独立数组进行排序。

One way of achieving this would be writing your own sorting methd which would take care of this, meaning when it swaps 2 elements in-place in the "original" array, it should swap 2 elements in-place in the "attribute" array.

实现这一点的一种方法是编写自己的排序方法来解决这个问题,这意味着当它在“原始”数组中就地交换 2 个元素时,它应该在“属性”数组中就地交换 2 个元素。

Here is a pseudocode on how you might try it.

这是有关如何尝试的伪代码。

function mySort(originals, attributes) {
    // Start of your sorting code here
        swap(originals, i, j);
        swap(attributes, i, j);
    // Rest of your sorting code here
}

回答by Andy Ray

I was looking for something more generic and functional than the current answers.

我正在寻找比当前答案更通用和更实用的东西。

Here's what I came up with: an es6 implementation (with no mutations!) that lets you sort as many arrays as you want given a "source" array

这是我想出的:一个 es6 实现(没有突变!),它允许您根据“源”数组对任意数量的数组进行排序

/**
 * Given multiple arrays of the same length, sort one (the "source" array), and
 * sort all other arrays to reorder the same way the source array does.
 * 
 * Usage:
 * 
 * sortMultipleArrays( objectWithArrays, sortFunctionToApplyToSource )
 * 
 * sortMultipleArrays(
 *   {
 *    source: [...],
 *    other1: [...],
 *    other2: [...]
 *   },
 *   (a, b) => { return a - b })
 * )
 * 
 * Returns:
 *   {
 *      source: [..sorted source array]
 *      other1: [...other1 sorted in same order as source],
 *      other2: [...other2 sorted in same order as source]
 *   }
 */
export function sortMultipleArrays( namedArrays, sortFn ) {
    const { source } = namedArrays;
    if( !source ) {
        throw new Error('You must pass in an object containing a key named "source" pointing to an array');
    }

    const arrayNames = Object.keys( namedArrays );

    // First build an array combining all arrays into one, eg
    // [{ source: 'source1', other: 'other1' }, { source: 'source2', other: 'other2' } ...]
    return source.map(( value, index ) =>
        arrayNames.reduce((memo, name) => ({
            ...memo,
            [ name ]: namedArrays[ name ][ index ]
        }), {})
    )
    // Then have user defined sort function sort the single array, but only
    // pass in the source value
    .sort(( a, b ) => sortFn( a.source, b.source ))
    // Then turn the source array back into an object with the values being the
    // sorted arrays, eg
    // { source: [ 'source1', 'source2' ], other: [ 'other1', 'other2' ] ... }
    .reduce(( memo, group ) =>
        arrayNames.reduce((ongoingMemo, arrayName) => ({
            ...ongoingMemo,
            [ arrayName ]: [
                ...( ongoingMemo[ arrayName ] || [] ),
                group[ arrayName ]
            ]
        }), memo), {});
}

回答by dy_

If performance matters, there is sort-idspackage for that purpose:

如果性能很重要,则有用于该目的的sort-ids包:

var sortIds = require('sort-ids')
var reorder = require('array-rearrange')

var name = ["Bob","Larry","Tom"];
var age =  [30, 20, 10];

var ids = sortIds(age)
reorder(age, ids)
reorder(name, ids)

That is ~5 times faster than the comparator function.

这比比较器功能快约 5 倍。

回答by bentael

inspired from @jwatts1980's answer, and @Alexander's answer hereI merged both answer's into a quick and dirty solution; The main array is the one to be sorted, the rest just follows its indexes

受到@jwatts1980's answer@Alexander's answer here 的启发,我将这两个答案合并为一个快速而肮脏的解决方案;主数组是要排序的数组,其余的只是跟随它的索引

NOTE: Not very efficient for very very large arrays

注意:对于非常大的数组不是很有效

 /* @sort argument is the array that has the values to sort
   @followers argument is an array of arrays which are all same length of 'sort'
   all will be sorted accordingly
   example:

   sortMutipleArrays(
         [0, 6, 7, 8, 3, 4, 9], 
         [ ["zr", "sx", "sv", "et", "th", "fr", "nn"], 
           ["zero", "six", "seven", "eight", "three", "four", "nine"] 
         ]
   );

  // Will return

  {  
     sorted: [0, 3, 4, 6, 7, 8, 9], 
     followed: [
      ["zr", th, "fr", "sx", "sv", "et", "nn"], 
      ["zero", "three", "four", "six", "seven", "eight", "nine"]
     ]
   }
 */

You probably want to change the method signature/return structure, but that should be easy though. I did it this way because I needed it

您可能想要更改方法签名/返回结构,但这应该很容易。我这样做是因为我需要它

var sortMultipleArrays = function (sort, followers) {
  var index = this.getSortedIndex(sort)
    , followed = [];
  followers.unshift(sort);
  followers.forEach(function(arr){
    var _arr = [];
    for(var i = 0; i < arr.length; i++)
      _arr[i] = arr[index[i]];
    followed.push(_arr);
  });
  var result =  {sorted: followed[0]};
  followed.shift();
  result.followed = followed;
  return result;
};

var getSortedIndex = function (arr) {
  var index = [];
  for (var i = 0; i < arr.length; i++) {
    index.push(i);
  }
  index = index.sort((function(arr){
  /* this will sort ints in descending order, change it based on your needs */
    return function (a, b) {return ((arr[a] > arr[b]) ? -1 : ((arr[a] < arr[b]) ? 1 : 0));
    };
  })(arr));
  return index;
};

回答by Bouke Versteegh

This solution (my work) sorts multiple arrays, without transforming the data to an intermediary structure, and works on large arrays efficiently. It allows passing arrays as a list, or object, and supports a custom compareFunction.

此解决方案(我的工作)对多个数组进行排序,无需将数据转换为中间结构,并且可以高效地处理大型数组。它允许将数组作为列表或对象传递,并支持自定义 compareFunction。

Usage:

用法:

let people = ["john", "benny", "sally", "george"];
let peopleIds = [10, 20, 30, 40];

sortArrays([people, peopleIds]);
[["benny", "george", "john", "sally"], [20, 40, 10, 30]] // output

sortArrays({people, peopleIds});
{"people": ["benny", "george", "john", "sally"], "peopleIds": [20, 40, 10, 30]} // output

Algorithm:

算法:

  • Create a list of indexes of the main array (sortableArray)
  • Sort the indexes with a custom compareFunction that compares the values, looked up with the index
  • For each input array, map each index, in order, to its value
  • 创建主数组的索引列表 (sortableArray)
  • 使用比较值的自定义 compareFunction 对索引进行排序,并使用索引进行查找
  • 对于每个输入数组,按顺序将每个索引映射到其值

Implementation:

执行:

/**
 *  Sorts all arrays together with the first. Pass either a list of arrays, or a map. Any key is accepted.
 *     Array|Object arrays               [sortableArray, ...otherArrays]; {sortableArray: [], secondaryArray: [], ...}
 *     Function comparator(?,?) -> int   optional compareFunction, compatible with Array.sort(compareFunction)
 */
function sortArrays(arrays, comparator = (a, b) => (a < b) ? -1 : (a > b) ? 1 : 0) {
    let arrayKeys = Object.keys(arrays);
    let sortableArray = Object.values(arrays)[0];
    let indexes = Object.keys(sortableArray);
    let sortedIndexes = indexes.sort((a, b) => comparator(sortableArray[a], sortableArray[b]));

    let sortByIndexes = (array, sortedIndexes) => sortedIndexes.map(sortedIndex => array[sortedIndex]);

    if (Array.isArray(arrays)) {
        return arrayKeys.map(arrayIndex => sortByIndexes(arrays[arrayIndex], sortedIndexes));
    } else {
        let sortedArrays = {};
        arrayKeys.forEach((arrayKey) => {
            sortedArrays[arrayKey] = sortByIndexes(arrays[arrayKey], sortedIndexes);
        });
        return sortedArrays;
    }
}

See also https://gist.github.com/boukeversteegh/3219ffb912ac6ef7282b1f5ce7a379ad

另见https://gist.github.com/boukeversteegh/3219ffb912ac6ef7282b1f5ce7a379ad

回答by Andrew Waller

How about:

怎么样:

var names = ["Bob","Tom","Larry"];
var ages =  ["10", "20", "30"];
var n = names.slice(0).sort()
var a = [];
for (x in n)
{
i = names.indexOf(n[x]);
a.push(ages[i]);
names[i] = null;
}
names = n
ages = a

回答by RobG

You could append the original index of each member to the value, sort the array, then remove the index and use it to re-order the other array. It will only work where the contents are strings or can be converted to and from strings successfuly.

您可以将每个成员的原始索引附加到值,对数组进行排序,然后删除索引并使用它重新排序另一个数组。它仅适用于内容为字符串或可以成功转换为字符串或从字符串转换的情况。

Another solution is keep a copy of the original array, then after sorting, find where each member is now and adjust the other array appropriately.

另一种解决方案是保留原始数组的副本,然后在排序后找到每个成员现在的位置并适当调整另一个数组。