I have an array of arrays
const arr = [
['foo', 'bar', 'hey', 'oi'],
['foo', 'bar', 'hey'],
['foo', 'bar', 'anything'],
['bar', 'anything']
]
I'm trying to get the strings that appears in all arrays, which in this case only bar.
I tried a lot of things with .filter but all looks confusing.
Is there a simple solution find a string that appear in all arrays?
Edit:
What I have tried
const arr = [
['foo', 'bar', 'hey', 'oi'],
['foo', 'bar', 'hey'],
['foo', 'bar', 'anything'],
['bar', 'anything']
]
const keySet = new Set()
arr.forEach(x => x.forEach(y => keySet.add(y)))
const uniqueKeys = Array.from(keySet)
console.log(uniqueKeys)
const res = uniqueKeys.filter(x => !arr.some(y => !y.includes(x)))
console.log(res)
You can do that in two steps:
Apply filter() on the first element of the array.(You can use an element)
Inside filter() use every() or the original array and check if that element is present in all the arrays.
const arr = [
['foo', 'bar', 'hey', 'oi'],
['foo', 'bar', 'hey'],
['foo', 'bar', 'anything'],
['bar', 'anything']
]
const res = arr[0].filter(x => arr.every(a => a.includes(x)));
console.log(res)
You could reduce the arrays by filtering with a Set.
const
array = [['foo', 'bar', 'hey', 'oi'], ['foo', 'bar', 'hey'], ['foo', 'bar', 'anything'], ['bar', 'anything']],
common = array.reduce((a, b) => a.filter(Set.prototype.has, new Set(b)));
console.log(common);
you can use combination of reduce and filter to get the intersection between all arrays:
const res = arr.reduce((acc, a) => acc.filter(value => a.includes(value) ), arr[0])
If you use lodash, the code would be simpler though:
const _ = require('lodash');
const res = _.intersection(...arr);
This is the first solution I could come up with, see if it's ok for you:
const arr = [
['foo', 'bar', 'hey', 'oi'],
['foo', 'bar', 'hey'],
['foo', 'bar', 'anything'],
['bar', 'anything']
];
const result = [];
arr[0].forEach(str => {
let present = true;
arr.slice(1).forEach(array => {
if (!array.includes(str))
present = false;
});
if (present)
result.push(str);
});
Use .filter(), .flat() and .every().
const arr = [
['foo', 'bar', 'hey', 'oi'],
['foo', 'bar', 'hey'],
['foo', 'bar', 'anything'],
['bar', 'anything']
];
var flat = arr.flat();
//▼ filters through the words to see which ones are all included
console.log(flat.filter(v => arr.every(a => a.includes(v)))
.filter((v, i, a) => a.indexOf(v) === i));
//▲ filter through the 4 bars to get only one
Use .filter like :
const arr = [
str: {'foo', 'bar',
'hey', 'oi'},
str: {'foo', 'bar',
'hey'},
str: {'foo', 'bar',
'anything'},
str: {'bar',
'anything'}
]
const result = arr.filter((arr) => arr.str === bar)
console.log(result)
//gives you bar lines
Related
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; }
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));
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)
I can't be able to figure out how to push items to same nested array like :
var arr = ['foo', 'bar', 'buz', 'hello'];
// It should be now look like this:
const output = {name: 'foo', children: [
{name: 'bar', children: [
{name: 'buz', children: [
{name: 'hello', children: []}
]}
]}
]};
Using reduce:
const arr = ['foo', 'bar', 'buz', 'hello'];
const result = arr.reverse().reduce((acc, val) => ({name: val, children: [acc]}), {});
console.log(result);
You can use reduceRight to create the output.
var arr = ['foo', 'bar', 'buz', 'hello'],
result = arr.reduceRight((r, name) => ({name, children: (!Object.keys(r).length ? [] : [r])}), {});
console.log(result);
Using a recursive function:
const arr = ['foo', 'bar', 'buz', 'hello'];
const f = (arr) => ({name: arr.shift(), children: arr.length ? [f(arr)] : []});
const output = f(arr);
console.log(output);
Using a recursive function
function nested (arr) {
if (arr.length === 1)
return { name: arr.shift(), children: [] };
else if (arr.length > 1)
return { name: arr.shift(), children: [nested(arr)] };
}
var array = ['foo', 'bar', 'buz', 'hello']
console.log(nested(array))
I now have an idea on how Array.reduce() method work, so posted another answer without recursive approach. I think it would be better for large tree structure.
The basic idea is that simply reverse the input array and then wrap the innermost object into another and so on.
let arr = ['foo', 'bar', 'buz', 'hello'];
function nest(arr) {
arr = arr.reverse();
let out = [];
arr.forEach(it => {
if(out.length === 0) out = {name: it, children: []}
else {
out = {name: it, children: [out]}
}
});
return out;
}
Is there a more concise way to functionally add an item to an array that is a property of an object?
Imperative:
secitems.sections.push("Test")
return secitems
Functional:
const R = require("ramada")
return Object.assign({}, secitems, {
sections: R.append(
"Test",
secitems.sections
)
})
My functional version seems too long and complicated compared to the imperative version. Is there a more concise way to write it?
Update (TL;DR)
I would do it like this:
const seclens = lensProp('sections');
over(seclens, append('Test'), secitems);
//=> {id: 123, sections: ['Foo', 'Bar, 'Test']}
There are a number of ways to do this more concisely. Some of them also solve for problems that your original code doesn't handle:
// This works fine
const secitems = {id: 123, sections: ['Foo', 'Bar']};
secitems.sections.push("Test")
secitems; //=> {id: 123, sections: ['Foo', 'Bar', 'Test']}
// But this is a problem
const secitems = {id: 123};
secitems.sections.push("Test")
secitems; //=> throws "secitems.sections is undefined"
My preferred method using Ramda would be to use lenses:
const secitems = {id: 123, sections: ['Foo', 'Bar']};
over(lensProp('sections'), append('Test'), secitems);
//=> {id: 123, sections: ['Foo', 'Bar, 'Test']}
The advantage of this is that the lens itself is useful in several contexts:
const seclens = lensProp('sections');
const getSections = view(seclens);
getSections(secitems); //=> ['Foo', 'Bar']
const setSections = set(seclens);
setSections(['Baz, Qux'], secitems)
//=> {id: 123, sections: ['Baz', 'Qux']}
setSections(['Baz', 'Qux'], {id: 456})
//=> {id: 456, sections: ['Baz', 'Qux']}
And if your data structure were to change, the only code that would need to change would be the lens definition itself:
const obj = {id: 123, secitems: {sections: ['Foo', 'Bar']}};
over(lensPath(['secitems', 'sections']), append('Test'), obj);
//=> {id: 123, secitems: {sections: ['Foo', 'Bar, 'Test']}}
Or
const seclens = lensPath(['secitems', 'sections']);
const getSections = view(seclens);
getSections(obj); //=> ['Foo', 'Bar']
const setSections = set(seclens);
setSections(['Baz, Qux'], obj)
//=> {id: 123, secitems: {sections: ['Baz', 'Qux']}}
setSections(['Baz', 'Qux'], {id: 456})
//=> {id: 456, secitems: {sections: ['Baz', 'Qux']}}
There is more information in Ramda's lens documentation.
const R = require('ramda')
return R.mergeWith(R.concat, secitems, { sections: ["Test"] })