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
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
Share Improve this question edited Jun 3, 2013 at 1:01 eyelidlessness 63.5k12 gold badges92 silver badges95 bronze badges asked Jun 3, 2013 at 0:28 Bob JBob J 3334 silver badges13 bronze badges 1- This seems to me like it's almost a key/value pair problem. Where aaaaa is the key for 7, ccccc the key for 1, and zzzzz the key for 3. Does your use case absolutely require that you maintain two distinct arrays or would you be open to combining them into a single array of objects similar to: arr = [{"key":"aaaaaa","value":7},{"key":"zzzzzz","value":3},........] ? – Mike Pugh Commented Jun 3, 2013 at 0:38
6 Answers
Reset to default 12I 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.
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]
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.
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}
]
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;
}
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