I know how to convert this:
const keys = [1, 2, 3];
To this:
[{key: 1, val: "q"}, {key: 2, val: "w"}, {key: 3, val: "e"}]
With a single mapping statement:
keys.map((x, i) => ({key: x, val: "qwe".charAt(i)}));
But I would actually like to get this:
{1: "q", 2: "w", 3: "e"}
Is there a neat way to do this in a single statement similar to the one above?
You can use reduce:
keys.reduce((accumulator, value, index) => { accumulator[index] = "qwe".charAt(index); return accumulator; }, {})
Ahhh, got it:
const objects = Object.assign({}, ...keys.map((x, i) => ({[x]: "qwe".charAt(i)})));
Though I would be happy to hear other suggestions as well as any notes on this one...
You can use reduce, and empty object as the initial value for the accumulator and insert property-value pairs on it:
const keys = [1, 2, 3];
let result = keys.reduce((obj, key, idx) => { obj[key] = 'qwe'[idx]; return obj }, {});
console.log(result)
Here is my solution.
const keys = [1, 2, 3];
const vals = "qwe";
const result = keys.reduce((prev, cur, idx) => ({
...prev,
[cur]: vals[idx]
}), {});
Related
I'm looking for a simple (and hopefully neat) way to convert an object of this form:
const object = {
key1: [a, b],
key2: [x, y, z]
};
To this:
[key1, a, key1, b, key2, x, key2, y, key2, z]
What I have so far is this:
const table = Object.entries(object).map(entry => [entry[0], ...entry[1]]);
Which gives me this:
[key1, a, b, key2, x, y, z]
How can I move forward?
You could take the entries of the object using Object.entries() and use a double nested .flatMap() one mapping the entries, and the other for mapping the actual value arrays to be [key, value] pairs like so:
const object = {
key1: ['a', 'b'],
key2: ['x', 'y', 'z']
};
const res = Object.entries(object).flatMap(([k, vals]) => vals.flatMap(v => [k, v]));
console.log(res);
Without flatMap you can use .concat() and .reduce() along with the spread syntax (...):
const object = {
key1: ['a', 'b'],
key2: ['x', 'y', 'z']
};
const res = Object.entries(object).reduce(
(acc, [key, vals]) => acc.concat(...vals.map(v => [key, v])), []);
console.log(res);
You can use Array.reduce on the object entries, pushing a key/value pair to the accumulator for each entry in the value:
const object = {
key1: ['a', 'b'],
key2: ['x', 'y', 'z']
};
const result = Object.entries(object)
.reduce((c, [k, a]) => {
a.forEach(v =>
c.push(k, v)
);
return c;
}, []);
console.log(result);
You can easily do that without using flat() method. You can do that using reduce and forEach to achieve this.
obj = {'key1': [1,2,3], 'key2': [4,5,6]};
ret = Object.keys(obj).reduce((prev, curr) => {
obj[curr].forEach(item => { prev = [...prev, curr, item]; });
return prev;
}, []);
console.log(ret);
On old Node versions, you can use Array#concat and spread syntax [].concat(...array) to flatten arrays, using the same overall approach as other answers:
const object = {
key1: [1, 2],
key2: [3, 4, 5]
};
const result = [].concat(
...Object.entries(object)
.map(([k, v]) =>
[].concat(...v.map(e => [k, e]))
)
);
console.log(result);
If you flatten things often, you can make it a function and bury it in your utilities file so it reads a bit cleaner:
const flat = a => [].concat(...a);
const flatMap = (a, fn) => flat(a.map(fn));
const object = {
key1: [1, 2],
key2: [3, 4, 5]
};
const result = flatMap(
Object.entries(object),
([k, v]) => flatMap(v, e => [k, e])
);
console.log(result);
Method 1, Using Object.entries, map and flat
Method 2, Using Object.entries, forEach and push
const object = {
key1: ["a", "b"],
key2: ["x", "y", "z"],
};
// Method 1, Using Object.entries, map and flat
const res = Object.entries(object)
.map(([key, arr]) => arr.map((value) => [key, value]))
.flat(2);
// Method 2, Using Object.entries, forEach and push
const toArr = (obj) => {
const res = [];
Object.entries(object).forEach(([key, arr]) =>
arr.forEach((value) => res.push(key, value))
);
return res;
};
console.log(res)
console.log(toArr(object));
using map and flat() you can achieve the result
const object = {
key1: ['a', 'b'],
key2: ['x', 'y', 'z']
};
Object.keys(object).map((e, i )=> {
return Object.values(object[e]).map( v => { return [e, v]}).flat()
}).flat()
// ["key1", "a", "key1", "b", "key2", "x", "key2", "y", "key2", "z"]
The most concise, clean and elegant way would be to combine Object.entries() and flat() with a degree sent as a parameter to the flat method.
Note: flat()- works on an array and flattens the array to the degree sent in the params. It returns a new flatten array. For example:
let arr = [1, 2, [3]];
let arrDegree1 = arr.flat();
console.log(arrDegree1) //[1,2,3];
let arr2 = [1, 2, [[3]]]
let arrDegreeTwo = arr2.flat(2);
console.log(arrDegreeTwo) //[1,2,3];
Thus Solution for this would be:
const o = {
key1: ['a', 'b'],
key2: ['x', 'y', 'z']
};
const result = Object.entries(o).reduce((acc,[key, values])=>{
return [...acc, (values.map(v=> [key,...v])) ];
},[]).flat(2);
console.log("Result",result);
let arr = [{key: 1, value: 10},
{key: 5, value: 20}]
let reformatArr = arr.map(obj => {
let tmp = {};
tmp[obj.key] = obj.value
return tmp;
});
//reformatArr is [{1: 10}, {5: 20}]
How can I reverse this process to its original format?I'm asking because I'm reformatting to send to my backend and want to reformat back when the data is returned.
You can destructure the first element of Object.entries for each object.
let reformatted = [{1: 10}, {5: 20}];
let res = reformatted.map(obj => {
const [[key, value]] = Object.entries(obj);
return {key,value};
});
console.log(res);
How is it possible to set the same value on multiple keys? For example I have the following object:
const obj = {
a: 5,
b: 5,
c: 5,
d: 6
}
Is there any easy way for example lets say I have array of [a, b, c] (keys) and to spread them in object and set them as keys with same value. Point is to look more classy for example:
const keys =[a, b, c]
const obj = {
[...keys]: 5
}
I know this would throw error but looking for some shorthand to achieve this
Take the array of keys and map each to an entry of the key and the 5 value:
const keys = ['a', 'b', 'c'];
const obj = {
...Object.fromEntries(
keys.map(key => [key, 5])
),
d: 6
};
console.log(obj);
Something like this works:
const obj = {};
const value = 5;
['a', 'b', 'c'].forEach(key => obj[key] = value);
You can build a zip function which takes an array of keys and a array of values and returns an object where each key/value pair is taken from their respective index:
const zip =
(ks, vs) =>
ks.reduce((o, k, i) =>
(o[k] = vs[i], o), {});
zip(['a', 'b', 'c'], [5, 5, 5]);
//=> {a: 5, b: 5, c: 5}
If you need to generate an array of 5:
Array(3).fill(5);
//=> [5, 5, 5]
Another solution could take a spreading of Object.assign with a spreaded array of objects.
const
keys = ['a', 'b', 'c'],
obj = { ...Object.assign(...keys.map(k => ({ [k]: 5 }))), d: 6 };
console.log(obj);
function(item)
{
return Object.keys(item).reduce((a, b) => ({ ...a, [b]:5 }),{});
}
I'm working with API data and I'm trying to build an object combining multiple arrays of data.
Current Arrays:
let name = [{name: "John"},{name: "Jane"},{name: "Doe",}]
let arr1 = ['bar', 'foo', 'foobar']
let arrX = ...
Desired Outcome:
let desiredOutcome = [
{
name: "John",
arr1: "bar", ...
},
{
name: "Jane",
arr1: "foo", ...
},
{
name: "Doe",
arr1: "foobar", ...
}]
I've been trying to play around with Object.assign() but I haven't had any luck:
var merge = Object.assign(obj, arr1 )
Is there a method or methods I could use?
Use .map() to add each element.
let name = [{name: "John"},{name: "Jane"},{name: "Doe",}]
let arr1 = ['bar', 'foo', 'foobar']
let result = name.map((a,i)=>{a.arr1 = arr1[i]; return a})
console.log(result)
You can do it using Array.map
Try the following:
let name = [{name: "John"},{name: "Jane"},{name: "Doe",}]
let arr1 = ['bar', 'foo', 'foobar'];
var result = name.map((o,i) =>Object.assign({"arr1" : arr1[i]},o));
console.log(result);
For an arbitrary count of arrays, you could take an array with the array of objects and the arrays of values and take short hand properties which preserves the name of the array and the values for adding to the result set with Object.assign.
var names = [{ name: "John" }, { name: "Jane" }, { name: "Doe" }],
arr1 = ['bar', 'foo', 'foobar'],
arrX = [1, 2, 3],
result = [names, { arr1 }, { arrX }]
.reduce((r, o) =>
(([k, a]) => a.map((v, i) => Object.assign({}, r[i], { [k]: v })))(Object.entries(o)[0])
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Maybe late but I'll provide some additional explanation on how to use .map:
The .map method creates a new array with the results of calling a provided function on every element in the calling array.
The method takes in one callback as argument. The callback itself can take predefined arguments. Here we will use the first two:
currentValue: e
index: i
Basically, the map method works by associating (literally mapping) each element of the looped array (here name) to the given returned value (here {name: e.name, arr1: arr1[i]}). Mapping is just a bijection between two arrays.
Another word on (e,i) => ({name: e.name, arr1: arr1[i]}):
It is the shorthand syntax called arrow function. It is similar to defining the callback function like so:
function(e,i) {
return { name: e.name, arr1: arr1[i] };
}
Full snippet will look like:
const name = [{name: "John"},{name: "Jane"},{name: "Doe",}]
const arr1 = ['bar', 'foo', 'foobar']
const result = name.map((e,i) => ({ name: e.name, arr1: arr1[i] }))
console.log(result)
How to make function take multiple variables from an array passed in as parameter?
Edited
For example:
Achieve this:
const inputObj = [
['Anna', 10, 'Monday'],
['Anna', 15, 'Wednesday'],
['Beatrice', 8, 'Monday'],
['Beatrice', 11, 'Wednesday'],
['Anna', 4, 'Wednesday'],
['Beatrice', 5, 'Monday'],
['Beatrice', 16, 'Monday']
]
// expected output:
const outputObj = [
[ 'Anna', 10, 'Monday' ],
[ 'Anna', 19, 'Wednesday' ],
[ 'Beatrice', 29, 'Monday' ],
[ 'Beatrice', 11, 'Wednesday' ]
]
const arr = [0, 2]
const someFunction = (obj, v, a) => {
const result = obj.reduce((acc, cur) => {
const key = `${cur[a[0]]}|${cur[a[1]]}`
if(!acc[key]) acc[key] = cur
else acc[key][1] += cur[v]
return acc
}, {})
return Object.values(result)
}
console.log(someFunction(inputObj, 1, arr))
with this:
const arr = [0, 2, 3, ...] // basically the array could contain any number of items.
const someFunction = (obj, v, objParams) => {
const result = obj.reduce((acc, cur) => {
const key = ???
...
}, {})
}
So that the function can be reused and it accepts custom-sized arrays, check if the column numbers in the array are the same, then adds the sum of the column that is passed in as v?
How to declare the variables from the objParams to achieve the same result as the code above does?
Also how to add v in the middle of cur?
Assuming objParams is an array of unknown size (strings in this example):
const objParams = ["c1", "c2", "c3"];
const key = objParams.join(']}|${cur[');
const built = '${cur[' + key + ']';
Built is:
${cur[c1]}|${cur[c2]}|${cur[c3]
With ES6 you can use the spread operator in the argument definition.
More reading about spread operator on MDN
function sum(...args) {
return args.reduce((result, value) => result + value, 0)
}
const numbers = [1, 2, 3];
console.log('sum', sum(2, 2));
console.log('sum', sum(...numbers));
console.log('sum', sum(1, 2, 1, ...numbers));
// get single args before accumulating the rest
function sum2(foo, bar, ...args) {
return args.reduce((result, value) => result + value, 0)
}
console.log('sum2', sum2(2, 2));
console.log('sum2', sum2(...numbers));
console.log('sum2', sum2(1, 2, 1, ...numbers));