Reputation: 7128
I want to sort a 2 dimensional array of integers. What is the simplest and most readable way to achieve this?
input:
[
[3,4,2],
[5,1,3],
[2,6,1],
]
output:
[
[1,1,2],
[2,3,3],
[4,5,6]
]
Upvotes: 1
Views: 696
Reputation: 386570
This is a general approach of nested array, which could have more nested arrays or different lengths.
It works by taking an array of indices to every value, a flat array of values and finally by assigning all values back to their place.
const
getIndices = (value, index) => Array.isArray(value)
? value.flatMap(getIndices).map(array => [index, ...array])
: [[index]],
setValue = (array, keys, value) => {
const last = keys.pop();
keys.reduce((a, i) => a[i] ??= [], array)[last] = value;
return array;
};
data = [[3, 4, 2], [5, 1, 3], [2, 6, 1]],
references = data.flatMap(getIndices),
result = data
.flat()
.sort((a, b) => a - b)
.reduce((r, v, i) => setValue(r, references[i], v), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 0
Reputation: 41
When working with nested arrays, its common to work from the inner most level and then step out. Using this method, we start with the inner arrays:
// Sorting the inner most array
var result = [];
[
[3,4,2],
[5,1,3],
[2,6,1],
].forEach(function(row) { // a for loop could work as well, this is just shorter.
result.push(row.sort(function(a, b) {
return a-b; // ascending
// return b-a; // descending
}));
});
Then, you sort the outer array. You cannot sort the outer array as a single number, so its necessary to decide on a method. Examples being: average of the array, lowest value, or highest value.
// Using the first value to sort the outer array.
[
[2,3,4],
[1,3,5],
[1,2,6],
].sort(function(a, b) {
return a[0]-b[0];
});
Alternatively
The wanted output "[[1,1,2],[2,3,3],[4,5,6]]" disregards the inner arrays so it doesn't seem practical. To do this however, we'd reconstruct all inner arrays into one, sort, and then rebuild a nested array assuming each new array is to have 3 values.
var oneDimensionalArray = [];
var finalArray = [];
[
[3,4,2],
[5,1,3],
[2,6,1],
].forEach(function(row) {
oneDimensionalArray = oneDimensionalArray.concat(row);
});
oneDimensionalArray.sort();
for (var i=0; i<oneDimensionalArray.length; i++) {
if (i%3==0) {
temp = [];
}
temp.push(oneDimensionalArray[i]);
if (i%3==2) { // 3 per line (0-2)
finalArray.push(temp);
}
}
Again, I don't see this having practical usefulness. It would be easier to leave them as a regular array or start with a different setup if all the data is to be used in a way that disregards grouping/array.
Upvotes: 1
Reputation: 43962
If you'd need the deeper arrays to be in order as well, I'd tackel it like so:
Flatten the arrays using flat()
, so get just a regular list
input.flat()
Sort them using a custom integer sort function
.sort((a, b) => a - b)
Re-create the second dimension
array_chunks(sortedArray, 3);
(Function used taken from this answer)
const input = [
[3,4,2],
[5,1,3],
[2,6,1],
];
const array_chunks = (array, chunk_size) => Array(Math.ceil(array.length / chunk_size)).fill().map((_, index) => index * chunk_size).map(begin => array.slice(begin, begin + chunk_size));
let result = array_chunks(input.flat().sort((a, b) => a - b), 3);
console.log(result);
[
[ 1, 1, 2 ],
[ 2, 3, 3 ],
[ 4, 5, 6 ]
]
Upvotes: 3