Spread an object into a table - javascript

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);

Related

How to form This JSON from this Javascript array of arrays?

I have this JavaScript array of arrays
arr1= [
['a', 'b'],
['1', '2']
]
And I need to form this JSON object
[
{
"label":"a",
"value":"1"
},
{
"label":"b",
"value":"2"
},
]
How do I do it?
Using Array#map:
const arr = [ ['a', 'b'], ['1', '2'] ];
const [labels, values] = arr;
const res = labels.map((label, index) => ({ label, value: values[index] }));
console.log(res);
Look at this ...
const entries = new Map([
['foo', 'bar'],
['baz', 42]
]);
const obj = Object.fromEntries(entries);
console.log(obj);
// expected output: Object { foo: "bar", baz: 42 }
Did you mean something like this?
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries
You could take an array with the keys of the wanted objects and reduce and map the items.
const
data = [['a', 'b'], ['1', '2']],
keys = ['label', 'id'],
result = data.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; }

Omit keys from an object which are present in another array in javascript

I have an object like this -
const obj = {
'a': 1,
'b': 2,
'c': 3,
'd': 4,
'e': 5
}
and an array containing keys belonging to the object,
const arr = ['a', 'b', 'd']
I want to return an object similar to obj but it shouldn't contain the keys present in arr,
i.e., I want an object which will be
const result = {
'c': 3,
'e': 5
}
How can I achieve this via Javascript?
With the new Object.fromEntries, it's easy:
const result = Object.fromEntries(Object.entries(obj).filter(([k, _]) => !arr.includes(k)))
Without it, it takes a bit more effort:
const result = Object.entries(obj).reduce((tot, [k, v]) => {
if (!arr.includes(k)) {
tot[k] = v;
}
return tot;
}, {})
You can copy the object and delete the listed properties:
const obj = {a:1,b:2,c:3,d:4,e:5};
const arr = ['a', 'b', 'd'];
const res = {...obj};
for (let k of arr) delete res[k];
console.log(res);
Note that this has a time complexity that is almost linear in terms of the number of properties involved, O(m+nlogn) (if delete is O(logn)), while Aplet's answer would have a quadratic time complexity: O(mn).
Using Object.entries, you can generate [key, value] pair from object as array.
And based on that, using Array.reduce, you can get the result you want.
const obj = {
'a': 1,
'b': 2,
'c': 3,
'd': 4,
'e': 5
};
const arr = ['a', 'b', 'd'];
const result = Object.entries(obj).reduce((acc, cur) => {
if (!arr.includes(cur[0])) {
acc[cur[0]] = cur[1];
}
return acc;
}, {});
console.log(result);
Array#reduce solution:
const obj = {'a': 1,'b': 2,'c': 3,'d': 4,'e': 5};
const arr = ['a', 'b', 'd'];
const o = Object.keys(obj)
.reduce((s, a) => (arr.indexOf(a) > -1 ? s : s[a] = obj[a], s), {});
console.log(o);
You could destructure the object and get the rest of it without unwanted keys.
const
object = { a: 1, b: 2, c: 3, d: 4, e: 5 },
without = ['a', 'b', 'd'],
result = without.reduce((r, k) => ({ [k]: _, ...r } = r, r), object);
console.log(result);
Traverse the object using JavaScript for..in loop. Check property using array indexOf method. If property name is not present in the array then put the property with value in ret variable.
const obj = {
a: 1,
b: 2,
c: 3,
d: 4,
e: 5,
};
const arr = ["a", "b", "d"];
ret = {};
for (let x in obj) if (arr.indexOf(x) === -1) ret[x] = obj[x];
console.log(ret);
You can do this using Object#entries then filter out those entries which are not in the arr and using Object#fromEntries reconstruct the object:
const obj = {'a': 1,'b': 2,'c': 3,'d': 4,'e': 5}, arr = ['a', 'b', 'd'];
const filterObj = (obj, arr) => {
const dataSet = new Set(arr);
return Object.fromEntries(Object.entries(obj)
.filter(([k, v]) => !dataSet.has(k)))
};
console.log(filterObj(obj, arr));
Another way to filter the object with the supplied keys but without using Object#fromEntries is by using Object#assign.
We would just filter the entries which are not in the given array, then map them to objects and pass those as parameters to the Object#assign:
const obj = {'a': 1,'b': 2,'c': 3,'d': 4,'e': 5}, arr = ['a', 'b', 'd'];
const filterObj = (obj, arr) => {
const keySet = new Set(arr);
const filteredEntries = Object.entries(obj).filter(([k, v]) => !keySet.has(k));
return Object.assign({}, ...filteredEntries.map(([k, v]) => ({[k]: v})));
}
console.log(filterObj(obj, arr));

How to set the same value on multiple keys

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 }),{});
}

How to map an array of arrays into an array of objects with a given keys array?

From an array of keys and an array of arrays, like this:
const keys = ['foo', 'bar'];
const vals = [
['a', 'A'],
['b', 'B']
];
How to get an array of objects like below ?
[
{'foo' : 'a', 'bar' : 'A'},
{'foo' : 'b', 'bar' : 'B'}
]
Maybe using lodash ?
You can use loash's _.zipObject() to create an object from an array of keys and values for each value array inside your 2d array using the _.map() method:
const keys = ['foo', 'bar']
const vals = [
['a', 'A'],
['b', 'B']
];
const res = _.map(vals, arr => _.zipObject(keys, arr));
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
If you prefer vanilla JS, then you could use Object.fromEntries() on a zipped array (created using .map()):
const keys = ['foo', 'bar']
const vals = [
['a', 'A'],
['b', 'B']
];
const res = vals.map(
arr => Object.fromEntries(arr.map((v, i) => [keys[i], v]))
);
console.log(res);
To be more generic, you can use Array.reduce() with index variable
const keys = ['foo', 'bar']
const values = [
['a', 'A'],
['b', 'B']
]
const mapped = values.map(val => val.reduce((acc, cur, i) => ({...acc, [keys[i]]: cur}),{}))
console.log(mapped)
With lodash/fp you can generate a function using _.flow(), that curries _.zipObject() with the keys, and the _.map() with the curried _.zipObject(), and then you can call it with vals to get the array of objects:
const fn = _.flow(_.zipObject, _.map);
const keys = ['foo', 'bar']
const vals = [
['a', 'A'],
['b', 'B']
];
const result = fn(keys)(vals);
console.log(result);
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
You can do it simply using reduce.
let keys = ['foo', 'bar'];
let values = [
['a', 'A'],
['b', 'B']
];
const res = values.reduce((a, [first, second]) => {
return [...a, {[keys[0]]: first, [keys[1]]: second}];
}, []);
console.log(res);
.as-console-wrapper{min-height: 100%!important; top:0}
let dataKeys = ['foo', 'bar'];
let dataValues = [
['a', 'A'],
['b', 'B']
];
let transformed = dataValues.reduce((result,item)=>{
result.push(
dataKeys.reduce((r,dk,index)=>{
let o = {};
o[dk]= item[index];
return {...r, ...o}
},{})
)
return result
},[]);
console.log(JSON.stringify(transformed,null,2));

Convert an array of keys into an object of key-value pairs

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]
}), {});

Categories

Resources