Sort two arrays the same way

前端 未结 12 2203
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-27 15:48

For example, if I have these arrays:

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

And I use name.sort

相关标签:
12条回答
  • 2020-11-27 16:37

    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

    0 讨论(0)
  • 2020-11-27 16:41

    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>
    
    0 讨论(0)
  • 2020-11-27 16:43

    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)

    0 讨论(0)
  • 2020-11-27 16:46

    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.

    0 讨论(0)
  • 2020-11-27 16:46

    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;
    };
    
    0 讨论(0)
  • 2020-11-27 16:47

    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/

    0 讨论(0)
提交回复
热议问题