Sort two arrays the same way

Javascript

Javascript Problem Overview


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:

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

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

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

Javascript Solutions


Solution 1 - Javascript

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:

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.

Also worth noting, method 2 is more efficient as you do not have to loop through the entire list twice in addition to the sort.

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

Solution 2 - Javascript

You could get the indices of name array using Array.from(name.keys()) or [...name.keys()]. Sort the indices based on their value. Then use map to get the value for the corresponding indices in any number of related arrays

const indices = Array.from(name.keys())
indices.sort( (a,b) => name[a].localeCompare(name[b]) )

const sortedName = indices.map(i => name[i]),
const sortedAge = indices.map(i => age[i])

Here's a snippet:

const name = ["Bob","Tom","Larry"],
      age =  ["10", "20", "30"],
      
      indices = Array.from(name.keys())
                     .sort( (a,b) => name[a].localeCompare(name[b]) ),
                     
      sortedName = indices.map(i => name[i]),
      sortedAge = indices.map(i => age[i])

console.log(indices)
console.log(sortedName)
console.log(sortedAge)

Solution 3 - Javascript

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.

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

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

Solution 4 - Javascript

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

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.

Solution 5 - Javascript

It is very similar to jwatts1980's answer (Update 2). Consider reading 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;
});

Solution 6 - Javascript

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

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.

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
}

Solution 7 - Javascript

inspired from @jwatts1980's answer, and @Alexander's answer here I 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

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

Solution 8 - Javascript

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

/**
 * 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), {});
}

Solution 9 - Javascript

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.

Solution 10 - Javascript

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:

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

Solution 11 - Javascript

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

Solution 12 - Javascript

Simplest explantion is the best, merge the arrays, and then extract after sorting: create an array

name_age=["bob@10","Tom@20","Larry@30"];

sort the array as before, then extract the name and the age, you can use @ to reconise where name ends and age begins. Maybe not a method for the purist, but I have the same issue and this my approach.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsupercoolvilleView Question on Stackoverflow
Solution 1 - Javascriptjwatts1980View Answer on Stackoverflow
Solution 2 - JavascriptadigaView Answer on Stackoverflow
Solution 3 - JavascriptBouke VersteeghView Answer on Stackoverflow
Solution 4 - Javascriptdy_View Answer on Stackoverflow
Solution 5 - Javascriptw35l3yView Answer on Stackoverflow
Solution 6 - JavascriptioreskovicView Answer on Stackoverflow
Solution 7 - JavascriptbentaelView Answer on Stackoverflow
Solution 8 - JavascriptAndy RayView Answer on Stackoverflow
Solution 9 - JavascriptRobGView Answer on Stackoverflow
Solution 10 - Javascriptbryan macleeView Answer on Stackoverflow
Solution 11 - JavascriptAndrew WallerView Answer on Stackoverflow
Solution 12 - JavascriptVinay NarayanView Answer on Stackoverflow