Reputation: 127
I have 2 lists/arrays:
[Examples]:
let labels = ["John", "Sophie", "Hannah", "Emilia"]
let data = [10, 40, 24, 25]
I want to sort both arrays with the order of data. (Each name corresponds with the value in the other array at the same index). I would use an object like this {name: value} but for my needs, they have to be seperate (at least the result). I have found a solution but i find it isnt very elegant.
[Desired Output Example]:
let data = [40, 25, 24, 10]
let labels = ["Sophie", "Emilia", "Hannah", "John"]
basically the other array has to be sorted with the same pattern that the data array will be sorted (numbers ascending)
Upvotes: 0
Views: 525
Reputation: 386540
You could take some abstract functions, inspired by
and transpose the data, sort it descending by index 1 and transpose the result. Then reassign by destructuring.
const
swap = fn => (a, b) => fn(b, a),
prop = k => o => o[k],
asc = (a, b) => (a > b) - (a < b),
desc = swap(asc),
transpose = array => array.reduce((r, a) => a.map((v, i) => [...(r[i] || []), v]), []),
take = pre => fn => (x, y) => fn(pre(x), pre(y)),
sortBy = fn => array => array.sort(fn),
pipe = (...functions) => input => functions.reduce((acc, fn) => fn(acc), input),
pipeline = pipe(
transpose,
sortBy(take(prop(1))(desc)),
transpose
);
let labels = ["John", "Sophie", "Hannah", "Emilia"],
data = [10, 40, 24, 25];
[labels, data] = pipeline([labels, data]);
console.log(...labels);
console.log(...data);
Upvotes: 2
Reputation: 5853
You can just map indices of labels
to indices of data
and sort based on values in data
(O(n^2logn)
complexity):
const labels = ["John", "Sophie", "Hannah", "Emilia"]
const data = [10, 40, 24, 25]
const sortedLabels = labels.sort((a, b) => data[labels.indexOf(b)] - data[labels.indexOf(a)])
const sortedData = data.sort((a, b) => b - a)
console.log(...sortedLabels)
console.log(...sortedData)
or performance version (O(nlogn)
complexity) in case of bigger arrays:
const labels = ["John", "Sophie", "Hannah", "Emilia"]
const data = [10, 40, 24, 25]
const merged = labels.map((e, i) => [e, data[i]])
.sort((a, b) => b[1] - a[1])
const sortedLabels = merged.map(e => e[0])
const sortedData = merged.map(e => e[1])
console.log(...sortedLabels)
console.log(...sortedData)
Upvotes: 1
Reputation: 315
let data = [40, 25, 24, 10];
let labels = ["Sophie", "Emilia", "Hannah", "John"];
const res = data.map((n, i) => [labels[i], n])
.sort((a, b) => a[1] - b[1])
.map(a => a[0])
console.log(res); // [ 'John', 'Hannah', 'Emilia', 'Sophie' ];
Upvotes: 1
Reputation: 214949
You can do this elegantly with the zip
function (see also Javascript equivalent of Python's zip function). zip
has an interesting property of being its own inverse, that is zip(zip([a, b])) === [a, b]
, so we zip both arrays into one, sort it and zip again.
let zip = (...a) => a[0].map((_, n) => a.map(b => b[n]))
let labels = ["John", "Sophie", "Hannah", "Emilia"]
let data = [10, 40, 24, 25];
[labels, data] = zip(...
zip(labels, data)
.sort((x, y) => y[1] - x[1])
)
console.log(...labels)
console.log(...data)
Upvotes: 5
Reputation: 43870
.map()
to merge the arrays into an array of arrays (2D array)
[[10, 'John'], [40, 'Sophie'], ...]
.sort()
by each sub-array's first element
arrArr[0][0] = 10, arrArr[1][0] = 40
for...of
loop to .push()
each element of each sub-array into a new array.Details are commented in demo below
let labels = ["John", "Sophie", "Hannah", "Emilia"];
let data = [10, 40, 24, 25];
// map() into an array of arrays
// ex. [[10, 'John'], [40, 'Sophie'],...]
let twoDArr = data.map((num, idx) => [num, labels[idx]]);
// sort() by the first element of each sub-array.
// ex. twoDArr[0][0] = 10, twoDarr[1][0] = 40
let sorted = twoDArr.sort((a, b) => b[0] - a[0]);
/*
for each sub-array of sorted 2D array
push sorted[i][0] into an empty array and
push sorted[i][1] into another empty array
*/
let keys = [];
let vals = [];
for (let [key, val] of sorted) {
keys.push(key);
vals.push(val);
}
console.log('data: '+keys);
console.log('labels: '+vals);
Upvotes: 1
Reputation: 12911
Here's an option that doesn't zip the related arrays, instead it creates an index array, sorts it by the relevant source array and then orders all the passed arrays by the sorted indexes.
const sortBySharedIndex = (...arrs) => {
const index = arrs[0].map((_, i) => i)
index.sort((a, b) => arrs[0][b] - arrs[0][a]);
return arrs.map(arr => index.map(i => arr[i]));
}
let data = [10, 40, 24, 25];
let labels = ["John", "Sophie", "Hannah", "Emilia"];
let [sortedData, sortedLabels] = sortBySharedIndex(data, labels);
console.log(...sortedData)
console.log(...sortedLabels)
Upvotes: 1
Reputation: 879
You can first merge both the arrays into one like
[
{label: ..., rank: ...},
{label: ..., rank: ...},
{label: ..., rank: ...},
]
Then sort the above array using the rank
property
And finally, map the array to extract either the label
or rank
properties
const labels = ["John", "Sophie", "Hannah", "Emilia"]
const ranks = [10, 40, 24, 25];
// Merge them both to a single array
const labelRankList = labels.map((label, i) => ({
label,
rank: ranks[i]
}));
const sortedList = labelRankList
.sort((a, b) => b.rank - a.rank) // Sort by rank
console.log("Labels : ", sortedList.map(x => x.label));
console.log("Data : ", sortedList.map(x => x.rank));
Upvotes: 1