Sort other arrays by order of specific array?

147 Views Asked by At

I have a bunch of arrays in this form:

var myRows = [
    [{idx: 0, val: 90}, {idx: 1, val: 75}, {idx: 2, val: 35}],
    [{idx: 0, val: 50}, {idx: 1, val: 17}, {idx: 2, val: 95}],
    [{idx: 0, val: 10}, {idx: 1, val: 24}, {idx: 2, val: 80}]
  // ...
];

Lets say I would like to sort the first row ascending by val, so it becomes:

[{idx: 2, val: 35}, {idx: 1, val: 75}, {idx: 0, val: 90}]

Is there an easy way to sort the remaining arrays, so that their order matches the idx-order of the sorted first row?

myArrays = [
    [{idx: 2, val: 35}, {idx: 1, val: 75}, {idx: 0, val: 90}]
  , [{idx: 2, val: 95}, {idx: 1, val: 17}, {idx: 0, val: 50}]
  , [{idx: 2, val: 80}, {idx: 1, val: 24}, {idx: 0, val: 10}]
  // ...
];

Maybe this is even possible without the idx property?

5

There are 5 best solutions below

0
Nina Scholz On BEST ANSWER

You could use sorting with map and apply the mapping for all items.

This proposal saves the indices, order the array and applies the order to all other arrays as well.

// the array to be sorted
var list = [[{ idx: 0, val: 90 }, { idx: 1, val: 75 }, { idx: 2, val: 35 }], [{ idx: 0, val: 50 }, { idx: 1, val: 17 }, { idx: 2, val: 95 }], [{ idx: 0, val: 10 }, { idx: 1, val: 24 }, { idx: 2, val: 80 }]];

// temporary array holds objects with position and sort-value
var mapped = list[0].map(function (el, i) {
    return { index: i, value: el.val };
})

// sorting the mapped array containing the reduced values
mapped.sort(function (a, b) {
    return a.value - b.value;
});

// rearrange all items in list
list.forEach(function (a, i, aa) {
    aa[i] = mapped.map(function (el) {
        return a[el.index];
    });
});

console.log(list);
.as-console-wrapper { max-height: 100% !important; top: 0; }

0
fafl On

When you drop the idx property, you can just use an array:

// Function copied from here: http://stackoverflow.com/a/36164530/5710637
var transpose = m => m[0].map((x,i) => m.map(x => x[i]))

var sortByRow = 0    
var myRows = [
  [90, 75, 35],
  [50, 17, 95],
  [10, 24, 80]
]
var myCols = transpose(myRows)
myCols.sort((x, y) => x[sortByRow] - y[sortByRow])
myRows = transpose(myCols)
console.log(myRows)

0
gnud On

You could do something like this.

var order = myRows[0].map(function(e) { return e.idx })
myRows.forEach(function(row) { 
    row.sort(function(a,b) { 
        return order.indexOf(a.idx) - order.indexOf(b.idx);
    });
});

This is very simple code just to demonstate the idea. It will probably be slow for very large arrays.

0
kukkuz On

Use a hash table to create a sorting criteria based on the first row - see demo below:

var myRows=[[{idx:0,val:90},{idx:1,val:75},{idx:2,val:35}],[{idx:0,val:50},{idx:1,val:17},{idx:2,val:95}],[{idx:0,val:10},{idx:1,val:24},{idx:2,val:80}]];

// sort the first row (as desired)
myRows[0].sort((a,b) => a.val - b.val);

myRows.forEach(function(c,i){
    if(i === 0){
      // create order criteria based on first row
      c.forEach(function(e, k){
        this[e.idx] = k;
      });
    } else {
      c.sort(function(a,b) {
        return this[a.idx] - this[b.idx];
      });
    }
 }, Object.create(null));
      
console.log(myRows);
.as-console-wrapper{top:0;max-height:100%!important;}

0
choz On

You can do the following which does,

  • Sort the first row of array1, and store their idxes in a temporary array2
  • Assign the remaining array with a temp property according to the first idx3
  • Sort the remaining array based on their temp property4 (Which is based on the first array)
  • Remove the temp property5

E.g.

var filteredRows = [];
var myRows = [
    [{idx: 0, val: 90}, {idx: 1, val: 75}, {idx: 2, val: 35}],
    [{idx: 0, val: 50}, {idx: 1, val: 17}, {idx: 2, val: 95}],
    [{idx: 0, val: 10}, {idx: 1, val: 24}, {idx: 2, val: 80}]
];

/* 1. Sort the first row */
myRows[0].sort(function(a, b) {
    return a.val - b.val;
});
filteredRows.push(myRows[0]);

/* 2. Get indexes */
var idxs = [];
for (var obj of myRows[0]) {
    idxs.push(obj.idx);
}

/* Handle the remaining array */
myRows.slice(1).map(function (val) {
    /* 3. Assign temp value */
    val.map(function (obj, i) {
        obj.temp = idxs[i];
    });

    /* 4. Sort them */
    val.sort(function (a, b) {
        return a.temp - b.temp;
    });

    /* 5. Remove temp value */
    val.map(function (obj, i) {
        delete obj.temp;
    });
});

console.log(JSON.stringify(myRows));