Change shape of an object of dataset based on array of keys - javascript

Suppose I have:
const KEYS = ['b', 'a', 'c']
const obj = {
2018: {a: 1, b: 2, c: 3},
2019: {a: 4, b: 5, c: 6},
2020: {a: 7, b: 8, c: 9},
}
This is what I would like to get:
const result = {
2018: {
a: [0, 1, 0],
b: [2, 0, 0],
c: [0, 0, 3]
},
2019: {
a: [0, 4, 0],
b: [5, 0, 0],
c: [0, 0, 6]
},,
2020: {
a: [0, 7, 0],
b: [8, 0, 0],
c: [0, 0, 9]
},
}
result['2018'] object has three keys. Each key value is an array that contains the values in the order that is set by KEYS using 0 as fill value.
How can I do something like this?
This is what I tried but obviously is more complicated than this:
const reshaped = Object.entries(obj).map(([key, value]) => {
return { [key]: Object.values(value) }
})
// [
// { 2018: [ 1, 2, 3 ] },
// { 2019: [ 4, 5, 6 ] },
// { 2020: [ 7, 8, 9 ] }
// ]

You could map the wanted keys in order abd build an array for each property.
const
KEYS = ['b', 'a', 'c'],
object = { 2018: { a: 1, b: 2, c: 3 }, 2019: { a: 4, b: 5, c: 6 }, 2020: { a: 7, b: 8, c: 9 } },
result = Object.fromEntries(Object.entries(object).map(([k, o]) => [
k,
Object.fromEntries(Object.entries(o).map(([l, v]) => [
l,
KEYS.map(m => l === m ? v : 0)
]))
]));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You could use a combination of Object.entries and Object.fromEntries to map the object and then just create a new array with the length of the KEYS arr.
const KEYS = ['b', 'a', 'c']
const obj = {
2018: {a: 1, b: 2, c: 3},
2019: {a: 4, b: 5, c: 6},
2020: {a: 7, b: 8, c: 9},
}
const result = Object.fromEntries( // Create obj from array of entries
Object.entries(obj).map(([key, value]) => [ // create array of entries from obj and map it
key,
Object.fromEntries( // do the same obj/arr transformation on the value
Object.entries(value).map(([subKey, subValue]) => {
const arr = new Array(KEYS.length).fill(0); // create new array of keys length and fill all zeroes
arr[KEYS.indexOf(subKey)] = subValue; // on the index of the key in the KEYS arr, set the value of the key
return [subKey, arr]; // return subValue
})
)
])
);
console.log(result);

Related

map array of objects based on set of properties

Suppose I have an object:
let array = [
{a: 1, b: 5, c: 9},
{a: 2, b: 6, c: 10},
{a: 3, b: 7, c: 11},
{a: 4, b: 8, c: 12}
];
then I have a dictionary:
const columns = [
{ key: 'a', value: 'a' },
{ key: 'b', value: 'b' },
]
I want to filter out properties that are not defined in columns.
I have tried
array.map((x) => ({"a": x.a, "b": x.b}))
Is there a way to use the data defined in columns instead of manually typing all the properties?
Desired output:
[
{
"a": 1,
"b": 5
},
{
"a": 2,
"b": 6
},
{
"a": 3,
"b": 7
},
{
"a": 4,
"b": 8
}
]
You could map entries and get the new objects.
let
array = [{ a: 1, b: 5, c: 9 }, { a: 2, b: 6, c: 10 }, { a: 3, b: 7, c: 11 }, { a: 4, b: 8, c: 12 }],
columns = [{ key: 'a', value: 'a' }, { key: 'b', value: 'b' }],
keys = columns.map(({ key }) => key),
result = array.map(o => Object.fromEntries(keys.map(k => [k, o[k]])));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could use this.
This uses just an array to hold the desired columns because I don't get why you would use a dictionary with key and value being the same.
let array = [
{ a: 1, b: 5, c: 9 },
{ a: 2, b: 6, c: 10 },
{ a: 3, b: 7, c: 11 },
{ a: 4, b: 8, c: 12 },
];
const desiredColumns = ["a", "b"];
const transformed = array.map(item => {
const obj = {};
desiredColumns.forEach(col => {
if(col in item){
obj[col] = item[col];
}
})
return obj;
})
console.log(array);
console.log(transformed)
Another, slightly less direct way using map() and reduce():
Create an array with all the keys we'll keep
Reduce the array to get the desired result
Add current key + value if key keep array
const array = [{a: 1, b: 5, c: 9}, {a: 2, b: 6, c: 10}, {a: 3, b: 7, c: 11}, {a: 4, b: 8, c: 12} ];
const columns = [{ key: 'a', value: 'a' }, { key: 'b', value: 'b' }, ];
const toKeep = columns.map(({ key }) => key).flat();
const result = array.map(a =>
Object.keys(a)
.reduce((prev, cur) => (toKeep.includes(cur)) ? { ...prev, [cur]: a[cur] } : prev, {})
);
console.log(result);
Result:
[
{
"a": 1,
"b": 5
},
{
"a": 2,
"b": 6
},
{
"a": 3,
"b": 7
},
{
"a": 4,
"b": 8
}
]

Efficient way to convert Object arrays into collection in Javascript

const myObj = {
a: [1, 2, 3],
b: [2, 4, 6],
c: [10, 20, 30]
}
Into
const myCollection = [
{a: 1, b: 2, c: 10},
{a: 2, b: 4, c: 20},
{a: 3, b: 6, c: 30}
]
I tried combinations of Object.entries, Object.keys and map but I'm always finding myself iterating twice or more over myObj and I'm not happy with any solution I came up with.
So what is the most efficient (in terms of time complexity) and elegant way that you can think to achieve that?
Just in case you'd need variable length:
const myObj = {
a: [1, 2, 3],
b: [2, 4, 6,8, 10],
c: [10, 20, 30, 40],
};
let myCollection = [];
Object.keys(myObj).forEach((k) => {
for (let i = 0; i < myObj[k].length; i++) {
if (!myCollection[i]) myCollection.push({});
myCollection[i][k] = myObj[k][i];
}
});
console.log(myCollection);
You could reduce the entries and map nested arrays.
const
object = { a: [1, 2, 3], b: [2, 4, 6], c: [10, 20, 30] },
result = Object
.entries(object)
.reduce((r, [k, a]) => a.map((v, i) => ({ ...r[i], [k]: v })), []);
console.log(result);
That can be done using Array.reduce. I have attached the conversion code.
const myObj = {
a: [1, 2, 3],
b: [2, 4, 6],
c: [10, 20, 30]
}
const myCollection = [
{a: 1, b: 2, c: 10},
{a: 2, b: 4, c: 20},
{a: 3, b: 6, c: 30}
]
const maxLength = Math.max(...Object.values(myObj).map(item => item.length));
const myObjKeys = Object.keys(myObj);
const result = [ ...Array(maxLength).keys() ].map((index) => {
return myObjKeys.reduce((acc, curKey) => {
if (myObj[curKey].length > index) {
acc[curKey] = myObj[curKey][index];
}
return acc;
}, {});
});
console.log(result);
Using ramdajs, I could suggest you a short way like below
const myObj = {
a: [1, 2, 3],
b: [2, 4, 6],
c: [10, 20, 30]
}
const res = R.map(
R.zipObj(R.keys(myObj)),
R.values(myObj)
)
console.log(res)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
In ramdajs homepage, criteria 3 in What's Different, it cited that
The parameters to Ramda functions are arranged to make it convenient for currying. The data to be operated on is generally supplied last.
You can use map() on Object.values and then use reduce() on each value.
const myObj = {
a: [1, 2, 3],
b: [2, 4, 6],
c: [10, 20, 30]
}
let keys = Object.keys(myObj);
const arr = Object.values(myObj).map((a) => a.reduce((ac, a, i) => ({...ac, [keys[i]]:a}), {}));
console.log(arr)

How grouped sort array of objects based on object's value?

I have array of objects like this:
var points = [{a: 4, b: 3, c:'parent'}, {a: 1, b:5, c:'child'}, {a: 5, b: 2, c:'child'}, {a: 1, b: 2, c:'parent'}, {a: 3, b: 1, c:'child'}];
I need to sort it on "a" object's value. But the problem is if it has the "c" object's value "parent" the "c" object's value "child" should be next object of that and shouldn't be sorted.
At last I expect to have this sorted points array:
var sortedPoints = [{a: 1, b: 2, c:'parent'}, {a: 3, b: 1, c:'child'} ,{a: 4, b: 3, c:'parent'}, {a: 1, b:5, c:'child'}, {a: 5, b: 2, c:'child'}];
You need to group parents and children, sort and get a flat array.
var points = [{ a: 4, b: 3, c: 'parent' }, { a: 1, b: 5, c: 'child' }, { a: 5, b: 2, c: 'child' }, { a: 1, b: 2, c: 'parent' }, { a: 3, b: 1, c: 'child' }],
sorted = points
.reduce((r, o) => {
if (o.c === 'parent') r.push([o]);
else r[r.length - 1].push(o);
return r;
}, [])
.sort(([{ a }], [{ a: b }]) => a - b)
.flat();
console.log(sorted);
.as-console-wrapper { max-height: 100% !important; top: 0; }

adding new values to existing object keys

I have an object with number values assigned to keys
obj1 = {a : 10
b : 5
c : 6 }
and I want to decrement each number to zero so that each key has all values in that range, i.e:
obj2 = {a : 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
b : 5, 4, 3, 2, 1, 0
c : 6, 5, 4, 3, 2, 1, 0}
ive tried .map, .apply, and several other attempts at iteration. how can I accomplish this?
You can create an array of object entries, and then use reduce() to create the result object:
const obj1 = {
a: 10,
b: 5,
c: 6
};
const obj2 = Object.entries(obj1).reduce((a, [k, v]) => ({
...a,
[k]: Array(v + 1).fill(0).map(_ => v--)
}), {});
console.log(obj2);
Here is a much simpler solution:
const obj1 = { a: 5, b: 6, c: 3 };
let obj2;
Object.keys(obj1)
.forEach((key) => {
const size = obj1[key];
obj2[key] = new Array(size + 1)
.fill(0)
.map((val, index) => size - index);
});
console.log(obj2);
The result thus obtained will be in this format:
{
a: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0],
b: [5, 4, 3, 2, 1, 0],
c: [6, 5, 4, 3, 2, 1, 0],
}
let obj1 = {
a: 10,
b: 5,
c: 6,
};
let obj2 = Object.fromEntries(Object.entries(obj1).map(([k, v]) => [k, [...Array(v)].map((_, i) => v - i)]));
console.log(obj2);
let obj1 = {a : 10, b : 5, c : 6}
let res = Object.entries(obj1).reduce((acc, cur) => {
return Object.assign(acc, {[cur[0]]: Array.from(Array(cur[1]+1).keys()).reverse().join()})
}, {})
console.log(res)

array.push(object) not pushed at the end of the loop in javascript

var temparray1 = [[1,3,4],[5,6,7],[8,9,10]];
var final = [];
var obj = {};
for(var temp in temparray1){
for(var test in temparray1[temp]){
obj.b = temparray1[temp][0];
obj.c = temparray1[temp][1];
obj.d = temparray1[temp][2];
}
console.log(obj);
final.push(obj);
}
current output
[{ b: 8, c: 9, d: 10 }
{ b: 8, c: 9, d: 10 }
{ b: 8, c: 9, d: 10 }]
expected Out put:
[{ b: 1, c: 3, d: 4 }
{ b: 5, c: 6, d: 7 }
{ b: 8, c: 9, d: 10 }]
i am running my javascript in node.js -v 8.1.x server
in the console at the end of the for loop it prints the required out put but not in the array push
var temparray = [[1, 3, 4], [5, 6, 7], [8, 9, 10]];
const final = temparray.map(a => ({ b: a[0], c: a[1], d: a[2] }));
console.log(final);
Probably, you set obj outside the for loop, therefore the props are overwritten and you push the same object multiple times into the array. Simply move the obj declaration into the loop. And you probably just need the outer loop.
Btw much shorter:
let final = temparray1.map(
([b,c,d]) => ({b,c,d})
);
You could use Array#map and return an object with the wanted properties.
var array = [[1, 3, 4], [5, 6, 7], [8, 9, 10]],
result = array.map(function (a) {
return { b: a[0], c: a[1], d: a[2] };
});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
With ES6, you could map the inner arrays as well with an array for the keys with Object.assign and spread syntax ....
var array = [[1, 3, 4], [5, 6, 7], [8, 9, 10]],
keys = ['b', 'c', 'd'],
result = array.map(a => Object.assign(...keys.map((k, i) => ({ [k]: a[i] }))));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here is what you wanted
var temparray1 = [[1,3,4],[5,6,7],[8,9,10]];
var final = [];
for(var temp in temparray1){
var obj = {};
obj['b'] = temparray1[temp][0];
obj['c'] = temparray1[temp][1];
obj['d'] = temparray1[temp][2];
final.push(obj);
}
console.log(final);
Hope this helps!

Categories

Resources