1

I have two arrays. I should do a normal sort on one (descending or ascending) and sort the other according to how the first array is sorted. This is because each element in the first array has a relationship with the same index element on the second array, and I must keep this relationship true. For example:

sortThis=[3,1,2];
sortAccording=["With 3","With 1","With 2];

I couldn't find any way to take the index changes from JavaScript's sort function.

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
Nogitsune
  • 27
  • 6
  • 1
    do they have to be in separate arrays? – Joseph Dec 22 '12 at 15:55
  • they are separate when i take them and i must output two separate arrays as well. but if merging and splitting them again solves the problem then its good. – Nogitsune Dec 22 '12 at 15:59

3 Answers3

3

Solution: To achieve that, you have to zip both arrays in just one. This is, given you have this two array:

sortThis=[3,1,2];
sortAccording=["With 3","With 1","With 2];

After zip them, you will have the following array:

zipped = [{a: 3, b: "With 3"}, {a: 1, b: "With 1"}, {a: 2, b: "With 2"}];

Then, you sort it by a in order to have:

zippedAndSorted = [{a: 1, b: "With 1"}, {a: 2, b: "With 2"}, {a: 3, b: "With 3"}];

What next?

Well, once you have this array sorted by what you want, you have to extract their values with the map function and finnaly you will have your two arrays sorted by the same criteria:

The code:

// your arrays
sortThis=[3,1,2];
sortAccording=["With 3","With 1","With 2"];

// the zip function    
function zip(a,b) {
    return a.map(function(aa, i){ return { i: aa, j: b[i]};} )
};               

// ziping and sorting the arrays
var zipped = zip(sortThis, sortAccording);
zippedAndSorted = zipped.sort(function(a,b){ return a.i - b.i; });

// your two sorted arrays
sortedThis = zippedAndSorted.map(function(a){ return a.i;});
sortedAccording = zippedAndSorted.map(function(a){ return a.j;});

You also can see it working here: http://jsfiddle.net/lontivero/cfpcJ/

Good luck!

lontivero
  • 5,235
  • 5
  • 25
  • 42
  • Using objects in `zip` is hardly a good idea. You'd be better off with array of arrays - this way both sorting and "unzipping" can be greatly simplified. – georg Dec 22 '12 at 19:05
  • @thg435: What's the difference? An array is just an object with numerical properties, and it would not be used differently in the code here. Theoretically, you'd need a tuple. – Bergi Dec 22 '12 at 19:17
  • @Bergi: the difference is that javascript knows how to sort a multidimensional array. – georg Dec 22 '12 at 19:22
  • @thg435: Huh, what? No, it does not. You still would need the custom compare function, especially when sorting numbers like the OP. – Bergi Dec 22 '12 at 19:24
  • How could javascript know that? – lontivero Dec 22 '12 at 19:28
  • @Bergi: try that in your browser `javascript:alert([[4,5],[2,3],[0,1]].sort())` – georg Dec 22 '12 at 19:29
  • 2
    @thg435: Then try `[[2,0],[10,1]].sort()` or `[["a",0], ["b",1], ["a,a",2],["a,_",3]].sort()` – Bergi Dec 22 '12 at 19:36
1

For example:

function zip(a, b) {
    var i = 0, j = 0, r = [];
    while(i < a.length && j < b.length)
        r.push([a[i++], b[j++]]);
    return r;
}

function unzip(r) {
    var a = [], b = [];
    for(var i = 0; i < r.length; i++) {
        a.push(r[i][0]);
        b.push(r[i][1]);
    }
    return [a, b];
}

r = zip(sortAccording, sortThis);
r.sort();
r = unzip(r);

sortAccording = r[0]
sortThis = r[1]

Another way:

result = sortAccording.
    map(function(elem, pos) { return [elem, pos]}).
    sort().
    map(function(elem) { return sortThis[elem[1]]})

Better implementations of zip and unzip (both working with variable number of arguments):

zip = function() {
    var args = [].slice.call(arguments, 0);
    return args[0].map(function(_, i) {
        return args.map(function(a) {
            return a[i]
        })
    })
}

unzip = function(a) {
    return a[0].map(function(_, i) {
        return a.reduce(function(y, e) {
            return y.concat(e[i])
        }, [])
    })
}
georg
  • 211,518
  • 52
  • 313
  • 390
0

I have a simple solution to this. Create a third array of indexes. Just sort that index array based on the sort of first array.

  var indexArray = [];
  for (var i=0; i < sortThis.length; i++) {
    indexArray[i] = i;
  }

  indexArray.sort(function(a, b) {
    return (sortThis[a] > sortThis[b]) ? 1 : (sortThis[a] === sortThis[b]) ? 0 : -1;
  });

  // Now you have the sorted index ready
  console.log("The first elements in the arrays are: " + sortThis(indexArray[0]) + " and " +  sortAccording(indexArray[0]));
closure
  • 7,412
  • 1
  • 23
  • 23