javascript, sort 2 array dependently

2020-03-01 09:07发布

问题:

for hours i've been trying to figure out how to sort 2 array dependently.

Let's say I have 2 arrays.

First one:

array1 = ['zzzzz', 'aaaaaa', 'ccccc'];

and the second one:

array2 = [3, 7, 1];

I sort the first one with array1.sort(); and it becomes [aaaaaa, cccccc, zzzzzz] now what I want is that the second one becomes [7, 1, 3]

I think it's quite simple but i'm trying to implement this in something a little more complex, im new and i keep mixing up things.

Thanks

回答1:

I would "zip" them into one array of objects, then sort that with a custom sort callback, then "unzip" them back into the two arrays you wanted:

var array1 = ['zzzzz', 'aaaaaa', 'ccccc'],
    array2 = [3, 7, 1],
    zipped = [],
    i;

for(i=0; i<array1.length; ++i) {
    zipped.push({
        array1elem: array1[i],
        array2elem: array2[i]
    });
}

zipped.sort(function(left, right) {
    var leftArray1elem = left.array1elem,
        rightArray1elem = right.array1elem;

    return leftArray1elem === rightArray1elem ? 0 : (leftArray1elem < rightArray1elem ? -1 : 1);
});

array1 = [];
array2 = [];
for(i=0; i<zipped.length; ++i) {
    array1.push(zipped[i].array1elem);
    array2.push(zipped[i].array2elem);
}

alert('Sorted arrays:\n\narray1: ' + array1 + '\n\narray2: ' + array2);

Here's a working fiddle.



回答2:

Here's a simple function that will do the trick:

function sortTogether(array1, array2) {
    var merged = [];
    for(var i=0; i<array1.length; i++) { merged.push({'a1': array1[i], 'a2': array2[i]}); }
    merged.sort(function(o1, o2) { return ((o1.a1 < o2.a1) ? -1 : ((o1.a1 == o2.a1) ? 0 : 1)); });
    for(var i=0; i<merged.length; i++) { array1[i] = merged[i].a1; array2[i] = merged[i].a2; }
}

Usage demo (fiddle here):

var array1 = ['zzzzz', 'aaaaaa', 'ccccc'];
var array2 = [3, 7, 1];
console.log('Before..: ',array1,array2);

sortTogether(array1, array2); // simply call the function

console.log('After...: ',array1,array2);

Output:

Before..:  ["zzzzz", "aaaaaa", "ccccc"] [3, 7, 1]
After...:  ["aaaaaa", "ccccc", "zzzzz"] [7, 1, 3] 


回答3:

Instead of two arrays of primitive types (strings, numbers) you can make an array of objects where one property of the object is string (containing "aaaaa", "cccccc", "zzzzzz") and another is number (7,1,3). This way you will have one array only, which you can sort by any property and the other property will remain in sync.



回答4:

It just so happens I had some old code lying around that might do the trick:

function arrVirtualSortGetIndices(array,fnCompare){
    var index=array.map(function(e,i,a){return i;});
    fnCompare=fnCompare || defaultStringCompare;
    var idxCompare=function (aa,bb){return fnCompare(array[aa],array[bb]);};
    index.sort(idxCompare);
    return index;

    function defaultStringCompare(aa,bb){
        if(aa<bb)return -1;
        if(bb<aa)return 1;
        return 0;
    }
    function defaultNumericalCompare(aa,bb){
        return aa-bb;
    }   
}

function arrReorderByIndices(array,indices){
    return array.map(
        function(el,ix,ar){
            return ar[indices[ix]];
        }
    );
}

var array1 = ['zzzzz', 'aaaaaa', 'ccccc'];
var array2 = [3, 7, 1];
var indices=arrVirtualSortGetIndices(array1);
var array2sorted=arrReorderByIndices(array2,indices);
array2sorted;

/*
7,1,3
*/

Sorry, I don't do 'fors'. At least not when I don't have to.

And fiddle.


Also, an alternative fiddle that sorts the results when given an array of objects like this:

given:

var list = [
    {str:'zzzzz',value:3},
    {str:'aaaaa',value:7},
    {str:'ccccc',value:1}
];

outputs:

[
  {str: "aaaaa", value: 7},
  {str: "ccccc", value: 1},
  {str: "zzzzz", value: 3}
]


回答5:

Assumption:

  • The arrays are the same length (this is implied by your question)
  • the contents can be compared with > and < (true in your example, but I wanted to make it clear that it was assumed here)

So then we can use an insertion sort.

var value,len = array1.length;
for (i=0; i < len; i++) {
        value = array1[i];
        for (j=i-1; j > -1 && array1[j] > value; j--) {
            array1[j+1] = array1[j];
            array2[j+1] = array2[j];
        }

        items[j+1] = value;
 }


回答6:

Using a solution found here to find the new indices after sorting an array, you can apply those indices to array2 like so.

function sortWithIndices(toSort) {
  for (var i = 0; i < toSort.length; i++) {
    toSort[i] = [toSort[i], i];
  }
  toSort.sort(function(left, right) {
    return left[0] < right[0] ? -1 : 1;
  });
  toSort.sortIndices = [];
  for (var j = 0; j < toSort.length; j++) {
    toSort.sortIndices.push(toSort[j][2]);
    toSort[j] = toSort[j][0];
  }
  return toSort;
}


var array1 = ['zzzz', 'aaaa', 'cccc'];
var array2 = [3, 7, 1];

// calculate the indices of array1 after sorting. (attached to array1.sortIndices)
sortWithIndices(array1);

// the final array after applying the sorted indices from array1 to array2
var final = [];

// apply sorted indices to array2
for(var i = 0; i < array1.sortIndices.length; i++)
    final[i] = array2[array1.sortIndices[i]];

// output results
alert(final.join(","));

JSFiddle Demo