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 :)
Related
I am trying to find all the string values from the array of objects and then format the keys.
//it works for a single object and string
// need help to implement an array of Object and string
function getKeyByValue(object, value) {
return Object.keys(object).find((key) => object[key] === value);
}
const data = [
{
AddressFlag: true,
BaseMasterTable: "DIMCUSTOMER",
ContextName: "Kunden",
DefaultOutputFormats: null,
HouseHoldColumn: null,
I18N: [],
ID: 5,
PrimaryKey: "CustomerKey",
}
];
const mapper = data.map((item) => {
const values = Object.values(item).filter((item) => typeof item === "string");
console.log(values);
// problem here;
//it's now taking a single object and a single string
// how can I take an array of objects and strings as parameters here
console.log(getKeyByValue(data[0], values[1]));
});
And finally output in this format
[
{fieldname: 'ContextName'},
{fieldName: 'PrimaryKey'},
{fieldName: 'BaseMasterTable'}
]
You can try this approach with Object.entries and map together. And flatMap to group all string data into a single array.
const data = [{
AddressFlag: true,
BaseMasterTable: "DIMCUSTOMER",
ContextName: "Kunden",
DefaultOutputFormats: null,
HouseHoldColumn: null,
I18N: [],
ID: 5,
PrimaryKey: "CustomerKey",
}];
const mapper = data.flatMap((item) => {
const result = Object.entries(item).filter(([key, value]) => typeof value === "string").map(([key, value]) => ({
fieldname: key
}));
return result
});
console.log(mapper)
Each object of array is iterated by .flatMap(). On each iteration the current object is converted into an array of pairs by Object.entries()
data.flatMap(obj => Object.entries(obj)
// [["AddressFlag", true], ["BaseMasterTable", "DIMCUSTOMER"], [...], ...]
Next, .flatMap() is used again, but this time as a filter. Since .flatMap() flattens it's returns by a level we can apply a ternary or if/else if/else statement with a empty array ([]) as the else or last part of a ternary. Doing so will cleanly return nothing (instead of the usual empty ("")). This technique is especially useful because you can return anything -- in the example, the condition is checking each pair second element (pair[1] which is originally the value) and if it's the given type (in the example is "string") the first element of the pair is returned as the value of an object (pair[0] which is originally the key). If it isn't the given type an empty array is returned.
data.flatMap(obj => Object.entries(obj).flatMap(pair =>
typeof pair[1] === "string" ? {"fieldName": pair[0]} : []))
// is "DIMCUSTOMER" a string ? return {"fieldName": "BaseMasterTable"} OR []
Details are commented in example
const data = [{
AddressFlag: true,
BaseMasterTable: "DIMCUSTOMER",
ContextName: "Kunden",
DefaultOutputFormats: null,
HouseHoldColumn: null,
I18N: [],
ID: 5,
PrimaryKey: "CustomerKey"
}];
/**
* Return an array of objects of which each object has a commonly shared key
* and a value derived from the key of an object of a given array. The object
* itself is determined by the given type of it's value.
* #param {array<object>} array - An array of objects
* #param {string} type - The type a value of an object property to accept
* #param {string} [newKey = "fieldName"] - The name of the commonly shared
* key of each object in the returned array. If undefined it defaults
* to "fieldName".
* #returns {array<object>} - An array of objects (see description above)
*/
function keysByType(array, type, newKey = "fieldName") {
return array.flatMap(obj =>
Object.entries(obj).flatMap(pair =>
typeof pair[1] === type ? {
[newKey]: pair[0]
} : []));
}
console.log(keysByType(data, "string"));
You can use flatMap and Object.entries() for this. Pretty simple:
const data = [
{
AddressFlag: true,
BaseMasterTable: "DIMCUSTOMER",
ContextName: "Kunden",
DefaultOutputFormats: null,
HouseHoldColumn: null,
I18N: [],
ID: 5,
PrimaryKey: "CustomerKey",
},
{
AddressFlag: true,
BaseMasterTable: "DIMCUSTOMER",
ContextName: "Kunden",
DefaultOutputFormats: null,
HouseHoldColumn: null,
I18N: [],
ID: 5,
PrimaryKey: "CustomerKey",
}
];
const result = data.flatMap(element => {
return Object.entries(element)
.filter(([,value]) => typeof value === "string")
.map(([key]) => ({fieldName: key}));
});
console.log(result)
This will duplicate keys, you can then filter if you need to.
This answer is almost the same approach as provided answers. Only difference is it is one loop less. I'm using flatMap here instead of filter & map. Something like this:-
const data = [{AddressFlag: true,BaseMasterTable: "DIMCUSTOMER",ContextName: "Kunden", DefaultOutputFormats: null, HouseHoldColumn: null, I18N: [], ID: 5, PrimaryKey: "CustomerKey", } ];
const result = data.flatMap(e=>Object.entries(e).flatMap(([fieldName,v])=>typeof v==='string' ? ({fieldName}) : []));
console.log(result);
I have a piece of data below. It's an object that contains 2 nested objects with arrays nested in those:
let data = {
obj1: {
names: ['joe'],
ages: false,
},
obj2: {
names: ['james'],
ages: true,
},
}
I want to return:
{
names: ['james','joe'],
ages: true,
}
Right now, I am doing this with:
const foo = Object.entries(data)[0][1] ?? [];
const foo2 = Object.entries(data)?.[1]?.[1] ?? [];
const finalData = {...foo, ...foo2 }
how can I clean that up using loDash's groupBy?
Use _.values() to get the two sub-objects, and then merge them using _.mergeWith(). If the values are an array, concat them, if not let _.mergeWith() handle the merge by returning undefined:
const data = {
obj1: {
names: ['joe', 'james'],
ages: false,
},
obj2: {
names: ['james'],
ages: true,
},
}
const result = _.mergeWith(
{}, ..._.values(data),
(a, b) => _.isArray(a) ? _.uniq([...a, ...b]) : undefined
)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous"></script>
This question already has answers here:
Convert Array to Object
(46 answers)
Closed 3 years ago.
I have the following array:
['2020-01-16', '2020-01-17', '2020-01-18']
I need to turn the array above into an object like this:
{
'2020-01-16': {selected: true, marked: true, selectedColor: 'blue'},
'2020-01-17': {selected: true, marked: true, selectedColor: 'blue'},
'2020-01-18': {selected: true, marked: true, selectedColor: 'blue'},
}
Is there a way I can do this?
Sure, using Array.reduce(), this is a pretty straightforward thing. The accumulator in the reduce function is simply an empty object, and each iteration through reduce, we create a new property with that array item's value as the property name, and define the object literal as the value of that property.
Hope this helps!
const myArray = ['2020-01-16', '2020-01-17', '2020-01-18'];
const myObject = myArray.reduce( (obj, item) => {
obj[item] = {selected: true, marked: true, selectedColor: 'blue'};
return obj;
}, {});
console.log(JSON.stringify(myObject) );
I would use reduce to handle this (documentation on reduce):
var arr = ['2020-01-16', '2020-01-17', '2020-01-18'];
arr.reduce(function(accumulator, val){
accumulator[val] = {selected: true, marked: true, selectedColor: 'blue'};
return accumulator;
}, {});
This will build out your object as it loops over the array. I like using reduce over forEach, when I can
Use .forEach() to iterate over all of them and build your object out.
var myKeys = ['2020-01-16', '2020-01-17', '2020-01-18'];
var myObject = {};
myKeys.forEach((key) => myObject[key] = {
selected: true,
marked: true,
selectedColor: 'blue'
});
console.log(myObject);
You'll likely need to change the logic as far as the specific data you're plugging in (for selected, marked, selectedColor), but this is the simplest approach generally.
I have a JS Object of the form stored in a variable keyData:
{type: "", label: "fname", title: "first name", …}
defaultvalue: ""
disabled: false
label: "fname"
readonly: false
required: "on"
title: "first name"
type: ""
__proto__: Object
I want to filter through these key-value pair and return a new object which contains the key-value pair with data available in them. For example, in this data, it should return title, required, and label only.
With that new filtered data, I want to map a react form with filtered keys as input types and filtered values as their value.
I am confused on how to solve this. I tried using Object.entries(keyData)
like this:
Object.entries(keyData).filter(x => console.log(x))
console.log(keyData)
on the console.log(keyData), it prints:
(2) ["type", ""]
(2) ["label", "fname"]
(2) ["title", "first name"]
(2) ["placeholder", ""]
(2) ["required", "on"]
(2) ["readonly", false]
(2) ["disabled", false]
I am unable to filter through this empty data further.
One option is to use reduce after you use Object.entries. You can then return an object only when the value is truthy.
const data = {
a: "foo",
b: false,
c: "bar",
d: null
};
const filtered = Object.entries(data).reduce((acc, [key, value]) => {
if (value) {
acc[key] = value;
}
return acc;
}, {});
console.log(filtered);
You need filter() and then reduce() to make it object
Object.entries(keyData).filter((key, value) => value).reduce((prev, curr) => {
prev[curr[0]] = curr[1];
return prev;
}, {});
I have some boolean values held within braces. What would a function look like to toggle each one to false? I've tried conf.column = !conf.column but that just sets the whole thing to false, understandably, not each individual boolean.
conf.column = {
a: true,
b: true,
c: true,
d: true,
e: true
};
Loop the object using for..in & change the value of the key
let column = {
a: true,
b: true,
c: true,
d: true,
e: true
};
for (let keys in column) {
column[keys] = !column[keys]
}
console.log(column)
You can do a forEach
Object.keys(conf.column).forEach(c => conf.column[c] = false);
Just loop them:
for (const key in conf.column)
conf.column[key] = !conf.column[key];
try this
Object.keys(conf.column)
.forEach(key => {
conf.column[key] = !conf.column[key]
})
read about Object.keys()
Non-mutating functional approach - construct a new object with the desired values and assign it to the original one.
conf.column = Object.keys(conf.column).reduce((result, key) => {
result[key] = false;
return result;
}, {});
Take a look you want to update the keys and not the object.
const conf = {}
conf.column = {
a: true,
b: true
}
Object.keys(conf.column).forEach((key) => conf.column[key] = !conf.column[key])
console.log(conf.column)
Many possible solutions. But be careful if your object has other attributes type than Boolean don't forget to test it.
var myObject = {
a: true,
b: true,
c: true,
d: undefined,
e: null,
f: "a string",
g: 21
}
for (var attribut in myObject) {
if (typeof(myObject[attribut]) === "boolean") {
myObject[attribut] = !myObject[attribut];
};
};