I am looking an elegant way in ES6 to transform this array:
var src = [{x:1,y:'a'},{x:2,y:'b'}];
To this array:
var desc = [[1,2],["a","b"]];
Which contains an array of all the properties and one array for all the values.
For this, i have written this code:
var src = [{x:1,y:'a'},{x:2,y:'b'}];
var prop1 = [];
var prop2 = [];
src.forEach(item => {
prop1.push(item.x)
prop2.push(item.y);
});
var desc = [prop1, prop2];
It works fine but it is quite long, so I am looking for an eventual improvement and a short code.
You name the props order (because the order of keys in object is not guaranteed) and then map over src array by extracting correspondend prop value.
var src = [{x:1,y:'a'},{x:2,y:'b'}]
var props = ['x', 'y'];
var result = props.map(prop => src.map(x => x[prop]))
console.log(result)
You can use .reduce():
let src = [{x: 1, y: 'a'}, {x:2, y: 'b'}];
let result = src.reduce((a, c) => (a[0].push(c.x), a[1].push(c.y), a), [[], []]);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Docs:
Array.prototype.reduce()
Array.prototype.push()
Comma Operator
You could iterate the array and then by the keys of the object and switch the outer and inner indices the target element.
var src = [{ x: 1, y: 'a' }, { x: 2, y: 'b' }],
desc = [];
src.forEach(o => Object.keys(o).forEach((k, i) => (desc[i] = desc[i] || []).push(o[k])));
console.log(desc);
Related
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; }
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; }
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);
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;
}
My js object:
data_obj = {'p1': 1, 'p2':2, 'p3':3}
my array
data_array = ['p1', 'p3']
Now, I want to filter the object based on the array. Expected result is
fil_obj = {'p1': 1, 'p3':3}
Now then, find the key having a maximum value. Expected result is
p3
Since I have object with thousands of items, I expect a very efficient solution.
Since I'm using d3js for this project, solution based on d3js like d3.max would be great.
You could iterate the wanted properties and return the max key.
var data_obj = { p1: 1, p2: 2, p3: 3},
data_array = ['p1', 'p3'],
result = data_array.reduce(function (r, a, i) {
return !i || data_obj[r] < data_obj[a] ? a : r;
}, undefined);
console.log(result);
I've never used d3, but it seems to me you can get the result pretty efficiently with a single call to .reduce():
var data_obj = {'p1': 1, 'p2':2, 'p3':3};
var data_array = ['p1', 'p3'];
var results = data_array.reduce((r,v)=>{
if (v in data_obj) {
r.data[v] = data_obj[v];
if (data_obj[v] > r.maxVal) {
r.maxKey = v;
r.maxVal = data_obj[v];
}
}
return r;
}, {data:{}, maxKey:null, maxVal:Number.NEGATIVE_INFINITY});
console.log(results);