Two foreach replacement JS - javascript

Could you please recommend the more elegant way of handling these case?
const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const getCombinations = () => {
const combinations = [];
arr1.forEach(el1 => {
arr2.forEach(el2 => {
combinations.push({
el1,
el2
});
});
});
return combinations;
};
console.log(getCombinations());

You can use a Array.flatMap() with Array.map():
const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const getCombinations = (a, b) =>
a.flatMap(el1 => b.map(el2 => ({ el1, el2 })));
const result = getCombinations(arr1, arr2);
console.log(result);

You could take a slightly more dynamic aproach by taking the cartesian product first and then map the objects with the wanted properties.
const
cartesian = (a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []),
takeKeys = keys => a => Object.assign(...a.map((v, i) => ({ [keys[i]]: v })))
array1 = [1, 2, 3],
array2 = ['a', 'b', 'c'],
result = [array1, array2]
.reduce(cartesian)
.map(takeKeys(['el1', 'el2']));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

what is equivalent of numpy.repeat() in javascript

a=['a','b','c']
s=[2,5,1]
a= numpy.repeat(a,s)
a: ['a','a','b','b','b','b','b','c']
Is there something equivalent in JavaScript ?
Not a straight forward equivalent but you can use Array.flatMap and Array.from to repeat the value according to the index in the second array :
const a = ['a', 'b', 'c']
const s = [2, 5, 1]
const result = a.flatMap((e, ndx) => Array.from({
length: s[ndx]
}, () => e));
console.log({
result
});
Flatmap and fill the array.
const
repeat = (values, counts) => values.flatMap((v, i) => Array(counts[i]).fill(v)),
a = ['a', 'b', 'c'],
s = [2, 5, 1],
result = repeat(a, s);
console.log(...result);

Spread an object into a table

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

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

Categories

Resources