I have two arrays and the data is combined, like:
[maximilian,moritz,hans] and
[5,1,2000]
Now I have to sort the first array based on the length of the names and keep the numbers at the right spot. The result should be:
[hans,moritz,maximilian]
[2000,1,5]
Normally you can combine both arrays, sort them and then separate them. Simple. But in my case the numbers have different lengths, so the right ordering isn't guaranteed.
If i combine and sort then, the result gonna be:
[moritz,hans,maximilian]
[1,2000,5]
and this is wrong.
Anyone has an idea how to fix this?
You could take the indices, sort them and map the values for both arrays.
var array1 = ['maximilian', 'moritz', 'hans'],
array2 = [5, 1, 2000],
indices = array1.map((_, i) => i);
indices.sort((a, b) => array1[a].length - array1[b].length);
array1 = indices.map(i => array1[i]);
array2 = indices.map(i => array2[i]);
console.log(array1);
console.log(array2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Create a single array of objects in the form of
var array = [{name: hans, number: 2000}, {name: moritz, number: 1}, {name: maximilian, number: 5}];
Then you can sort by the key name without having to worry about the numbers
You can also use Map to sort both arrays:
let a1 = ['maximilian', 'moritz', 'hans'],
a2 = [5, 1, 2000];
(map => {
a1.sort(({length:s1}, {length:s2}) => s1 - s2);
a2 = a1.map(s => map.get(s));
})(new Map(a1.map((v, i) => [v, a2[i]])));
console.log(a1);
console.log(a2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Docs:
Map
Array.prototype.sort()
Array.prototype.map()
Object Destructuring
Arrow Functions
I would make an array of objects, combining both arrays into one, then sort them by key, and then splitting them again.
const arr1 = [ 'maximilian', 'moritz', 'hans' ]
const arr2 = [5, 1, 2000]
const tmp = [];
for (let i = 0; i < arr1.length; i++) {
tmp.push({ key: arr1[i], val: arr2[i] });
}
tmp.sort((a, b) => a.val < b.val);
console.log(tmp);
const keys = tmp.reduce((sub, elem) => { sub.push(elem.key); return sub }, []);
const vals = tmp.reduce((sub, elem) => { sub.push(elem.val); return sub }, []);
console.log(keys);
console.log(vals);
Related
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]
]
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 ]
]
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.
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; }
I have 3 arrays:
keys = ['first','second']
ycor = [200,400]
xcor = [[375,75],[75]]
I am thinking of how to get them to:
[
{
'first': 200,
'second': [375,75]
},
{
'first': 400,
'second': [75]
}
]
The primary attempt was to use the forEach() function, but only managed to reach a 2 sided case and unidentifiable by node.
var result = []
keys.forEach((i,v,w) => result[i] = (xcor[v],ycor[w]))
Is it possible at all?
You could reduce the values arrays and map new objects.
This approach uses spread syntax ... for taking the old object at the same index j of the result array.
var keys = ['first', 'second'],
ycor = [200, 400],
xcor = [[375, 75], [75]],
result = [ycor, xcor].reduce(
(r, a, i) => a.map((v, j) => ({ ...r[j], [keys[i]]: v })),
[]
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Suppose I have an array as such
var arr = [ [1,2,3],[4,5,1]]
How do I check if the columns are in ascending order?
For first column 1<4 returns true but the last column returns false as 3 is not less than 1.
The result should return an array of the columns that returns false
I would do it by first transposing the matrix (simply because its easier to deal with in js) and then map over each column (converting them from a set of numbers into a bool using Array#every).
const arr = [
[1,2,3],
[4,5,1]
];
const transpose = (arr) => Array(arr[0].length)
.fill(0)
.map((_, colIndex) => {
return Array(arr.length)
.fill(0)
.map((_, rowIndex) => {
return arr[rowIndex][colIndex];
});
});
const arr2 = transpose(arr);
const arr3 = arr2.map(col => {
let previousValue = -Infinity;
return col.every(v => {
const tmp = previousValue < v;
previousValue = v;
return tmp;
});
});
console.log(arr);
console.log(arr2);
console.log(arr3);
One possible solution is to use Array.map() over the first inner array, and then check if you found some element on a particular column that is not in order using Array.some():
var arr = [
[1, 2, 3],
[4, 5, 1],
[6, 7, 2]
];
let res = arr[0].map((n, cIdx) =>
{
return !arr.some((inner, rIdx) => rIdx > 0 && inner[cIdx] < arr[rIdx - 1][cIdx]);
});
console.log(res);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
To find the "columns" with the two values in descending order, you can use parallel arrays. Here is a succinct version of the code for that. (The second snippet is more verbose and provides further explanation.)
var arr = [ [1,2,3], [4,5,1] ], result = [];
arr[0].forEach((n, i) => { // n is the number, i is the index
if(arr[0][i] > arr[1][i]){ result.push(i); } // if descending, remember this index
});
console.log(result); // Logs `[2]` (an array with the index of the third column)
If you want to change which "column" the values are in so that they will be in ascending order, you could do it like this. When you find a "misplaced" value, store it in a temporary variable to make room. Then you can assign the two values to their "correct" locations.
const bigArr = [ [1,2,3], [4,5,1] ],
a1 = bigArr[0],
a2 = bigArr[1],
resultArr = [],
len = Math.min(a1.length, a2.length); // Uses min in case they have different lengths
for(let i = 0; i < len; i++){
if(a1[i] > a2[i]){ // Checks each position, and exchanges values if necessary
exchangeValuesInParallelArrays(a1, a2, i);
resultArr.push(i); // Adds this index to the results array
}
}
console.log(bigArr); // Logs `[ [1,2,1], [4,5,3] ]`
console.log(resultArr) // Logs `[2]`
function exchangeValuesInParallelArrays(arr1, arr2, index){
let tempStorage = arr1[index];
arr1[index] = arr2[index];
arr2[index] = tempStorage;
}
My data is animalCount: {Tiger: 3, Leopard: 6, Rat: 1}
So I need to have 1st array
name :['Tiger', 'Leopard', 'Rat']
2nd array
count: [3, 6, 1]
Is it possible to obtain the same?
Sure, just use:
const names = Object.keys(animalCount);
const values = Object.values(animalCount);
As others have mentioned, you can use:
var name = Object.keys(animalCount);
var count = Object.values(animalCount);
If you, for some reason, needed to manipulate or change them while creating these arrays, you could also use a for i in animalCount loop, like so:
var animalCount = {Tiger: 3, Leopard: 6, Rat: 1};
var array1 = [];
var array2 = [];
for(i in animalCount){
if(animalCount.hasOwnProperty(i)){
array1.push(i);
array2.push(animalCount[i]);
}
}
console.log(array1);
console.log(array2);
How about
var name = [];
var count = [];
for(var prop in animalCount){
name.push(prop);
count.push(animalCount[prop]);
}
This way we're sure the order is preserved.
JS supports this natively.
var name = Object.keys(animalCount);
var count = Object.values(animalCount);
See:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys for Object.keys and
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values for Object.values
You could take a single loop and reduce the entries of the object by iterating the key/value array for pushing the items.
var animalCount = { Tiger: 3, Leopard: 6, Rat: 1 },
names = [],
count = [],
result = Object
.entries(animalCount)
.reduce((r, a) => (a.forEach((v, i) => r[i].push(v)), r), [names, count]);
console.log(names);
console.log(count);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Suppose I generate two arrays
One that holds Array of numbers:
[5.65, 3.25, 4.34, 6.78]
And another array that holds objects with some information in them
[car.object1, car.object2, car.object3, car.object4]
And the objects in second array are related to the numbers in first array. So object1 is related to 5.65, object2 to 3.25 and so on.
So I want to sort the array 1 in an ascending order and at the same time sort the array 2 also.
So the result should be:
[3.25, 4.34, 5.65, 6.78]
&
[car.object2, car.object3, car.object1, car.object4]
My Approach: (You can just ignore the below answer as I think it is wrong. It does not work.)
var all = [];
var A = [5.65, 3.25, 4.34, 6.78];
var B = ['store.object1', 'store.object2', 'store.object3', 'store.object4'];
for (var i = 0; i < B.length; i++) {
all.push({
'A': A[i],
'B': B[i]
});
}
all.sort(function(a, b) {
return a.A - b.A;
});
A = [];
B = [];
for (var i = 0; i < all.length; i++) {
A.push(all[i].A);
B.push(all[i].B);
}
console.log(A, B);
You could use a temporary array with the indices and sort it with the values of the first array. Then map the sorted array with the values of array1 and array2.
I use strings for the second array, instead of missing objects.
var array1 = [5.65, 3.25, 4.34, 6.78],
array2 = ['car.object1', 'car.object2', 'car.object3', 'car.object4'],
temp = array1.map(function (_, i) { return i; });
temp.sort(function (a, b) { return array1[a] - array1[b]; });
array1 = temp.map(function (a) { return array1[a]; });
array2 = temp.map(function (a) { return array2[a]; });
console.log(temp);
console.log(array1);
console.log(array2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Unless you want to implement the sort yourself, one simple way is to combine the entries from the number array with the entries from the object array (at least briefly), sort that, and then (if necessary) extract the result:
// Setup
var car = {
object1: {name: "object1"},
object2: {name: "object2"},
object3: {name: "object3"},
object4: {name: "object4"}
};
var nums = [5.65, 3.25, 4.34, 6.78];
var objs = [car.object1, car.object2, car.object3, car.object4];
// Combine
var joined = [];
nums.forEach(function(num, index) {
joined[index] = {num: num, object: objs[index]};
});
// Sort
joined.sort(function(a, b) {
return a.num - b.num;
});
// Extract
nums = [];
objs = [];
joined.forEach(function(entry, index) {
nums[index] = entry.num;
objs[index] = entry.object;
});
console.log(nums);
console.log(objs);
.as-console-wrapper {
max-height: 100% !important;
}
But rather than combine, sort, and extract, I'd probably just maintain a single array and add each number to its relevant object, so they always travel together.
Here is an ES6 way to do it:
let a = [5.65, 3.25, 4.34, 6.78];
let b = [{ x:1 }, { x:2 }, { x:3 }, { x: 4}];
[a, b] = a.map( (n, i) => [n, b[i]] ) // zip the two arrays together
.sort( ([n], [m]) => n-m ) // sort the zipped array by number
.reduce ( ([a,b], [n, o]) => [[...a, n], [...b, o]], [[],[]] ); // unzip
console.log(JSON.stringify(a));
console.log(JSON.stringify(b));
I've helped myself with an object containing car.object as the key and it's number as the value. Seems easy&quick solution.
var obj = [{'car.object1': 5.65}, {'car.object2': 3.25}, {'car.object3': 4.34}, {'car.object4': 6.78}],
objs = obj.sort((a,b) => a[Object.keys(a)] - b[Object.keys(b)]);
console.log(objs.map(v => Object.keys(v)[0]));
console.log(objs.map(v => v[Object.keys(v)]));
console.log(objs);
.as-console-wrapper {
max-height: 100% !important;
}