I want to merge this array using or || operator
[[true,false,false],[false,false,false],[false,false,true]]
so that the output is
[true,false,true]
is this possible with map or reduce or similar?
Edit: Sorry for the unclear question - yes it was to vertically merge all sub arrays together. So the following input:
[[true,false,false],[false,false,false],[false,false,true],[false,false,true]]
would produce the same output:
[true,false,true]
You don't really need the || when you use some:
var array = [[true, false, false], [false, false, false], [false, false, true]];
var result = array[0].map( (_, i) => array.some(a => a[i]));
console.log(result);
You could reduce the arrays with mapping the same index values.
var array = [[true, false, false], [false, false, false], [false, false, true]],
result = array.reduce((a, b) => a.map((c, i) => b[i] || c));
console.log(result);
you can do it in the following way
let arr = [[true,false,false],[false,false,false],[false,false,true]];
arr = arr.map(function(element){
return element.reduce(function(a, b){
return (a|b);
})
})
console.log(arr);
Related
I want to compare to Nested Objects and create a new Object with all the missing fields.
I have a main JSON respone in a Javascript Object:
var MainFile = {
"id": 0,
"name": 'test',
"info": {
"data_11":0,
"data_12":0,
"data_13":{
"data_131":0,
"data_132":0,
"data_133":0,
},
},
"info2": {
"data_21":0,
"data_22":0,
"data_23":0,
}
}
And now I have x amount of objects that I have to compare against the main and check that object has all the same keys.
var obj2 = {
"id": 0,
"info": {
"data_11":0,
"data_13":{
"data_131":0,
"data_133":0,
},
},
"info2": {
"data_22":0,
"data_23":0,
}
}
}
So seeing both objects we can see the differences. I've tried recursive functions to check with Object.hasProperty, but I never get the result I'm looking for. that would be an object that would look like the following:
result = {
"id": true,
"name": false,
"info": {
"data_11":true,
"data_12":false,
"data_13":{
"data_131":false,
"data_132":true,
"data_133":false,
},
},
"info2": {
"data_21":true,
"data_22":false,
"data_23":false,
}
}
Has anyone tried anything like this? I've looked everywhere, but everyone compares the value of the key, not if the actual key is missing in the nested array.
Any help would be appreciated
One advantage of keeping around a collection of useful utility functions is that we can combine them quickly to create new functionality. For me, this function is as simple as this:
const diffs = (o1, o2) =>
hydrate (getPaths (o1) .map (p => [p, hasPath (p) (o2)]))
We first call getPaths (o1), which yields
[
["id"],
["name"],
["info", "data_11"],
["info", "data_12"],
["info", "data_13", "data_131"],
["info", "data_13", "data_132"],
["info", "data_13", "data_133"],
["info2", "data_21"],
["info2", "data_22"],
["info2", "data_23"]
]
Then we map these into path entry arrays, using hasPath against our test object, which yields:
[
[["id"], true],
[["name"], false],
[["info", "data_11"], true],
[["info", "data_12"], false],
[["info", "data_13", "data_131"], true],
[["info", "data_13", "data_132"], false],
[["info", "data_13", "data_133"], true],
[["info2", "data_21"], false],
[["info2", "data_22"], true],
[["info2", "data_23"], true]
]
This is very similar to the format used by Object .fromEntries, except that the keys are arrays of values rather than single strings. (Those values could be strings for object keys or integers for array indices.) To turn this back into an object, we use hydrate, which in turn depends upon setPath. Again hydrate tis a generalization of Object .fromEntries, and setPath is a recursive version of setting a value.
Put together it looks like this:
// utility functions
const getPaths = (obj) =>
Object (obj) === obj
? Object .entries (obj) .flatMap (
([k, v]) => getPaths (v) .map (p => [Array .isArray (obj) ? Number(k) : k, ... p])
)
: [[]]
const setPath = ([p, ...ps]) => (v) => (o) =>
p == undefined ? v : Object .assign (
Array .isArray (o) || Number .isInteger (p) ? [] : {},
{...o, [p]: setPath (ps) (v) ((o || {}) [p])}
)
const hydrate = (xs) =>
xs .reduce ((a, [p, v]) => setPath (p) (v) (a), {})
const hasPath = ([p, ...ps]) => (obj) =>
p == undefined ? true : p in obj ? (ps .length > 0 ? hasPath (ps) (obj [p]) : true) : false
// main function
const diffs = (o1, o2) =>
hydrate (getPaths (o1) .map (p => [p, hasPath (p) (o2)]))
// sample data
const MainFile = {id: 0, name: "test", info: {data_11: 0, data_12: 0, data_13: {data_131: 0, data_132: 0, data_133: 0}}, info2: {data_21: 0, data_22: 0, data_23: 0}}
const obj2 = {id: 0, info: {data_11: 0, data_13: {data_131: 0, data_133: 0}}, info2: {data_22: 0, data_23: 0}};
// demo
console .log (diffs (MainFile, obj2))
.as-console-wrapper {max-height: 100% !important; top: 0}
The functions that this is built upon are all generally useful for many problems, and I simply keep them in my back pocket. You may note that this also handles arrays; that just comes along with those functions
diffs ({foo: ['a', 'b', 'c']}, {foo: ['a', 'b']})
//=> {"foo": [true, true, false]}
I also want to note that if you're looking for a more complete diff function, an old answer by user Mulan is a great read.
I have this 2 dimensional array =
0: (3) [true, false, false]
1: (3) [true, true, false]
2: (3) [true, true, true]
3: (3) [false, false, false]
The position in the array represents the same in each i.e 0 = "Learner" 1 = "Manager", 2 = "ClientAdmin"
I want a new 2 dimensional array that looks like below
0: (3) ["Learner"]
1: (3) ["Learner", "Manager"]
2: (3) ["Learner", "Manager", "ClientAdmin"]
3: (3) []
I have tried
selectedAudienceMandatoryArrayText = []
this.selectedAudienceMandatoryArray.forEach( (isArray, index) => {
if (isArray[0] == true) {
this.selectedAudienceMandatoryArrayText[index].push("Learner");
}
if (isArray[1] == true) {
this.selectedAudienceMandatoryArrayText[index].push("Manager");
}
if (isArray[2] == true) {
this.selectedAudienceMandatoryArrayText[index].push("ClientAdmin");
}
}
but I get the error: Cannot read property 'push' of undefined
What is the most efficient way to do this. ES6 solutions welcome.
You could check if the flag is set, then take the value from roles with the index or return an empty array.
const
roles = ["Learner", "Manager", "ClientAdmin"],
data = [[true, false, false], [true, true, false], [true, true, true], [false, false, false]],
result = data.map(a => a.flatMap((f, i) => f ? roles[i] : []));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
selectedAudienceMandatoryArrayText = [];
this.selectedAudienceMandatoryArray.forEach(isArray => {
const roles = [];
if (isArray[0]) roles.push('Learner');
if (isArray[1]) roles.push('Manager');
if (isArray[2]) roles.push('ClientAdmin');
selectedAudienceMandatoryArrayText.push(roles);
}
You could push to a new array for each loop, and at the end, push that to the other array. This reduces having to keep track of the index for the outer array.
I am finding it hard to work out the best way to take multiple arrays of the same length and merge them into a single array of true values. So if true is in the index position, the new array should have true, else just leave false.
const array1 = [true, true, false, false, true]
const array = [true, false, false, true, false]
Output is:
[true, true, false, true, true]
You can do this with map. It will generate new array for you. Inside map there are certain arguments you can pass current value and iteration using which you will get the data from second array and then put an OR || condition to get the expected output.
const array1 = [true, true, false, false, true];
const array = [true, false, false, true, false];
const output = array1.map((val,i)=>val || array[i]);
console.log(output);
You can use map() and check any of e OR array[i] is true, here e belong to each element of array1 and array[i] means each element of array respectively.Finally, it will make a newArray after conditional checking inside the map function.
const array1 = [true, true, false, false, true];
const array = [true, false, false, true, false];
var newArray = array1.map((e, i) => Boolean(e | array[i]));
console.log(newArray)
What would be a nice elegant functional solution for anding two boolean arrays in ES6?
const a1 = [true, false, false]
const a2 = [true, true, false]
should result in:
[true, false, false]
Use can use Array#map to iterate the 1st array, and get the value of the 2nd array using the index (the 2nd param in the callback):
const a1 = [true, false, false]
const a2 = [true, true, false]
const result = a1.map((b, i) => b && a2[i]);
console.log(result);
Lets say I have an object
filter: {
"ID": false,
"Name": true,
"Role": false,
"Sector": true,
"Code": false
}
I want to set all keys to false (to reset them). What's the best way to do this, I'd like to avoid looping with foreach and stuff. Any neat one liner?
Well here's a one-liner with vanilla JS:
Object.keys(filter).forEach(v => filter[v] = false)
It does use an implicit loop with the .forEach() method, but you'd have to loop one way or another (unless you reset by replacing the whole object with a hardcoded default object literal).
Using lodash, mapValues is a graceful, loop-free way:
filter = {
"ID": false,
"Name": true,
"Role": false,
"Sector": true,
"Code": false
};
filter = _.mapValues(filter, () => false);
If you want to do this with Underscore.js, there is an equivalent, but with a slightly different name:
filter = _.mapObject(filter, () => false);
In either case, the value of filter will be set to:
{ ID: false,
Name: false,
Role: false,
Sector: false,
Code: false }
If you're not using ES6, here is its ES5 counterpart.
Object.keys(filter).forEach(function(key, value) {
return filter[key] = false;
})
If you don't want to modify the array, here's an ES6 alternative that returns a new one:
Object.fromEntries(Object.keys(filter).map((key) => [key, false]))
Explanation:
Object.keys returns the object's keys:
Object.keys({ a: 1, b: 2 }) // returns ["a", "b"]
Then we map the result ["a", "b"] to [key, false]:
["a", "b"].map((key) => [key, false]) // returns [['a', false], ['b', false]]
And finally we call Object.fromEntries that maps an array of arrays with the form [key, value] to an Object:
Object.fromEntries([['a', false], ['b', false]]) // returns { a: false, b: false }
A small line of code compatible with all browsers:
for(var i in your_object) your_object[i] = false;
With ES6 features one-liner without mutation:
{
...Object.keys(filter).reduce((reduced, key) => ({ ...reduced, [key]: false }), {})
}
hasOwnProperty must be used
```
for(var i in your_object) {
if (Object.hasOwnProperty.call(your_object, i)) {
your_object[i] = false;
}
}
```
In case you are dealing with 'scope' variables, this might be a better solution.
Object.keys(filter).reduce(function(accObj, parseObj) {
accObj[parseObj] = false;
return accObj;
}, {});
Here's what i would call a neat one-liner solution:
const filtered = Object.assign(...Object.keys(filter).map(k => ({ [k]: false })));
Demo:
const filter = {
'ID': false,
'Name': true,
'Role': false,
'Sector': true,
'Code': false
};
const filtered = Object.assign(...Object.keys(filter).map(k => ({ [k]: false })));
console.log(filtered);
We are basically converting the object into an array using Object.assign() so we can use the map() fucntion on it to set each propety value to false, then we convert the array back to an object using the Object.assign() with the spread operator :)