5

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?

kukkuz
  • 41,512
  • 6
  • 59
  • 95
Đinh Carabus
  • 3,403
  • 4
  • 22
  • 44

5 Answers5

2

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; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

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)
fafl
  • 7,222
  • 3
  • 27
  • 50
1

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.

gnud
  • 77,584
  • 5
  • 64
  • 78
1

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));
choz
  • 17,242
  • 4
  • 53
  • 73
0

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;}
kukkuz
  • 41,512
  • 6
  • 59
  • 95