I have an object as below:
obj = {
'fruita' : 'eat',
'fruitb' : 'eat',
'fruitc' : 'throw',
'fruitd' : 'throw'
}
output = {
'eat' : ['fruita','fruitb'],
'throw' : ['fruitc','fruitd']
}
How to apply _.groupBy in order to get the list of eat and throw fruits seperately?
We can turn our object to an array of key-value pairs:
var keyValues = Object.keys(obj).map(key => ({ key, value: obj[key] }));
And then we can perform a reduce to construct our object:
var values = keyValues.reduce((acc, kv) => {
if (typeof acc[kv.value] === 'undefined') {
acc[kv.value] = [];
}
acc[kv.value].push(kv.key);
return acc;
}, {});
No lodash necessary!
You could use a for..in loop to set properties of output object to values of obj , push obj properties to items within array at output
var obj = {
'fruita' : 'eat',
'fruitb' : 'eat',
'fruitc' : 'throw',
'fruitd' : 'throw'
}
var output = {};
for (var prop in obj) {
if (!output[obj[prop]]) {
output[obj[prop]] = [];
output[obj[prop]].push(prop)
} else {
output[obj[prop]].push(prop)
}
}
console.log(output)
Related
i have an nested object as such:
options = {
religous: {
kosher: {
value: 'Kosher',
chosen: false
},
halal: {
value: 'Halal',
active: false
},
},
vegan: {
value: 'Vegan',
active: false
}
}
It contains nested objects of varying sizes. I would like to get an Array containing the values of any value propery. So for the above object the desired output would be:
['Kosher', 'Halal', 'Vegan']
Order doesn't really matter.
I tried to do so recursively as such:
getListOfLabels = obj => {
const lst = []
for (let key in obj) {
if (obj[key].value) lst.push(obj[key].value)
else return getListOfLabels(obj[key])
}
return lst
}
but I keep getting a RangeError: Maximum call stack size exceeded error.
Any suggestions?
The for...in loop assigns the key. To get the value use obj[key]. If the key is value add to lst, if it's an object, call getListOfLabels on it, and spread the results into lst.push():
const options = {"religous":{"kosher":{"value":"Kosher","chosen":false},"halal":{"value":"Halal","active":false}},"vegan":{"value":"Vegan","active":false}}
const getListOfLabels = obj => {
const lst = []
for (let key in obj) {
const val = obj[key] // get the value
if (key === 'value') lst.push(val) // if the key name is "value" push to lst
else if(typeof val === 'object') lst.push(...getListOfLabels(val)) // if type of value is object, iterate it with getListOfLabels and push the results into lst
}
return lst
}
const result = getListOfLabels(options)
console.log(result)
You could take a recursive approach and check if the object contains a value key.
function getValues(object, key) {
if (key in object) return [object[key]];
return Object.values(object).reduce((r, v) => {
if (v && typeof v === 'object') r.push(...getValues(v, key));
return r;
}, []);
}
var options = { religous: { kosher: { value: 'Kosher', chosen: false }, halal: { value: 'Halal', active: false } }, vegan: { value: 'Vegan', active: false } };
console.log(getValues(options, 'value'));
Here's a succinct approach using reduce :-D
const getValues = options => Object.values(options)
.reduce((acc, optionObj) => (
optionObj.value ? [ ...acc, optionObj.value ] : [
...acc,
...Object.values(optionObj).reduce((arr, { value }) => ([ ...arr, value ]), [])
]), [])
I would like to filter all boolean values from an json object in javascript. I managed to get it working on a simple json object but in my case I have got a nested one. Here is an example of the object. I dont know how to manage this structure.
{
"User1":
{
"age":15,
"country":"sw",
"glasses":true,
"car":true,
"zip":1223,
"name":"Frank"
},
"User2":
{
"age":23,
"country":"fr",
"glasses":false,
"car":true,
"zip":5577,
"name":"Mike"
}
}
And as a result I would like to receive something like this:
{
"User1":{
"glasses":true,
"car":true
},
"User2":{
"glasses":false,
"car":true
}
}
const result = {};
for(const [key, value] of Object.entries(input)) {
const {glasses, car} = value;
result[key] = {glasses, car};
}
Just iterate over the objects entries and make some destructuring on the inner objects. Or if you really want every boolean:
const result = {};
for(const [key, value] of Object.entries(input)) {
const out = result[key] = {};
for(const [innerKey, innerValue] of Object.entries(value)) {
if(typeof innerValue === "boolean")
out[innerKey] = innerValue;
}
}
For actual JSON string, the JSON.parse reviver parameter can be used to exclude or modify values:
var j = '{"User1":{"age":15,"country":"sw","glasses":true,"car":true,"zip":1223,"name":"Frank"},"User2":{"age":23,"country":"fr","glasses":false,"car":true,"zip":5577,"name":"Mike"}}';
var o = JSON.parse(j, (k, v) => typeof v == 'number' || typeof v == 'string' ? void 0 : v);
console.log(o);
If you don't know which keys will be booleans, you can do it like this.
Let's say you assign that object to a variable.
var myObject = {
"User1": {
"age":15,
"country":"sw",
"glasses":true,
"car":true,
"zip":1223,
"name":"Frank"
},
"User2": {
"age":23,
"country":"fr",
"glasses":false,
"car":true,
"zip":5577,
"name":"Mike"
}
}
Then you can loop through the object and assign the filtered results to myBooleans.
var myBooleans = {};
Object.keys(myObject).forEach(function(key) {
var myNewUserObject = {};
Object.keys(myObject[key]).forEach(function(userKey) {
if (typeof myObject[key][userKey] === 'boolean') {
myNewUserObject[userKey] = myObject[key][userKey];
}
});
myBooleans[key] = myNewUserObject;
});
There is probably a pretty way to do with with n levels of object using recursion. But this will work for the shape of the data you provided.
Try this
function parse(obj , targetObject) {
var k;
if (obj instanceof Object) {
for (k in obj){
if(typeof(obj[k]) === "boolean"){
targetObject[k] = obj[k];
}
if(obj[k] instanceof Object) {
targetObject[k] = {};
parse(obj[k],targetObject[k]);
}
}
}
};
Call like this:
var target = {};
parse(myObj , target);
Hope this helps
This is how you can filter all the boolean values from object -
let input = {
"User1": {
"age": 15,
"country": "sw",
"glasses": true,
"car": true,
"zip": 1223,
"name": "Frank"
},
"User2": {
"age": 23,
"country": "fr",
"glasses": false,
"car": true,
"zip": 5577,
"name": "Mike"
}
};
let output = {};
Object.entries(input).map(([key, value], index) => {
output[key] = {};
Object.entries(value).
filter(([k, v], i) => typeof v === "boolean").
map(([k, v], i) => {
output[key][k] = v;
})
});
console.log(output);
I'm fetching json data with ajax. Then I want to output it in Griddle using griddle-react. The problem is I cannot convert my array to a Griddle readable array.
After the ajax fetch i made a callback function:
function convert(obj) {
console.log(obj);
Object.keys(obj).forEach(function (key) {
let format = JSON.stringify(obj[key]);
console.log(format);
self.setState(() => ({ data: key[format] }));
});
}
The first console.log output looks like this:
{
{
"BTC": {
"opening_price": "9845000",
"closing_price": "9967000",
"min_price": "9814000",
"max_price": "10047000",
"average_price": "9928071.5654",
"units_traded": "7242.04659594",
"volume_1day": "7242.04659594",
"volume_7day": "73491.92898643",
"buy_price": "9967000",
"sell_price": "9968000"
},
}
}
My functions makes it look like this: (second console.log):
{
"opening_price": "9846000",
"closing_price": "9965000",
"min_price": "9814000",
"max_price": "10047000",
"average_price": "9929422.0905",
"units_traded": "7200.46713802",
"volume_1day": "7200.467F13802",
"volume_7day": "73395.33311647",
"buy_price": "9959000",
"sell_price": "9964000"
}
I want it to convert to the following array, basically adding the name item, and thereafter Griddle can read it:
{
"name": "BTC",
"opening_price": "9845000",
"closing_price": "9967000",
"min_price": "9814000",
"max_price": "10047000",
"average_price": "9928071.5654",
"units_traded": "7242.04659594",
"volume_1day": "7242.04659594",
"volume_7day": "73491.92898643",
"buy_price": "9967000",
"sell_price": "9968000"
},
What I'm doing wrong here? I'm sure its pretty close to what I want, but I can't figure it out at this point.
You can use Object.entries to get the keys and values. Use Object.assign to make new objects
var obj = {
"BTC": {"opening_price": "9845000","closing_price": "9967000","min_price": "9814000","max_price": "10047000","average_price": "9928071.5654","units_traded": "7242.04659594","volume_1day": "7242.04659594","volume_7day": "73491.92898643","buy_price": "9967000","sell_price": "9968000"}
}
var newObj = Object.entries(obj).reduce((c, [i, v]) => Object.assign(c, {name: i}, v), {});
console.log(newObj);
If you have several keys, you can use map
var obj = {
"BTC": {"opening_price": "9845000","closing_price": "9967000","min_price": "9814000","max_price": "10047000","average_price": "9928071.5654","units_traded": "7242.04659594","volume_1day": "7242.04659594","volume_7day": "73491.92898643","buy_price": "9967000","sell_price": "9968000"},
"OTH": {"opening_price": "9845000","closing_price": "9967000","min_price": "9814000","max_price": "10047000","average_price": "9928071.5654","units_traded": "7242.04659594","volume_1day": "7242.04659594","volume_7day": "73491.92898643","buy_price": "9967000","sell_price": "9968000"},
}
var newArr = Object.entries(obj).map(([i, v]) => Object.assign({}, {name: i}, v));
console.log(newArr);
Without including date property
var obj = {
"KNC": {"opening_price": "2731","closing_price": "2788","min_price": "2693","max_price": "2849","average_price": "2790.5368","units_traded": "3178032.25814499211673","volume_1day": "3178032.25814499211673","volume_7day": "110687333.315264505902311000","buy_price": "2783","sell_price": "2788"},
"date": "1525269153470"
}
var newObj = Object.entries(obj).reduce((c, [i, v]) => i !== 'date' ? Object.assign(c, {name: i}, v) : c, {});
console.log(newObj);
Can you update your function to have this line in it?
obj[key]["name"] = key
function convert(obj) {
console.log(obj);
Object.keys(obj).forEach(function (key) {
obj[key]["name"] = key;
let format = JSON.stringify(obj[key]);
console.log(format);
//self.setState(() => ({ bithumbData: key[format] }));
});
}
function convert(obj){
var parentKey = Object.keys(obj)[0];//Getting parent first element key
obj = obj[parentKey];
var newObj = {}; //Creating new empty jason object
newObj['name'] = parentKey; //key apply as name element to new jason object
for(var key in obj) //looping each child element
newObj[key] = obj[key]; //child applying to new jason object
return newObj;
}
console.log(JSON.stringify(convert(obj)));
I have this nested object:
{
"PINS" : {
"2017" : {
"Nov-2017" : {
"VJkRWX7pTSl_5w1Np" : {
"pin" : "6K3jP5vLyN",
"say": "Hello"
},
"MsdsXiO9G9mwM3Qa" : {
"pin" : "hnPKh7ywvT",
"say": "Hello"
}
},
"Dec-2017" : {
"Mm35Gjb-nY0k2TV" : {
"pin" : "xWwaNNE2XG",
"say": "Hello"
},
"WzajCLEJmJHmzg0" : {
"pin" : "vMU1mKbZAi",
"say": "Hello"
}
}
},
"2018" : {
"Jan-2018" : {
"Wf8E1unVaOh03a43" : {
"pin" : "qXJCQREATD",
"say": "Hello"
},
"JZqP8fVCLSja6J82v" : {
"pin" : "o5D8S8Lvtb",
"say": "Hello"
}
},
"Feb-2018" : {
"lMMAKNLy8jtnnXAN" : {
"pin" : "9zDuHcw6qH",
"say": "Hello"
},
"e9EV3HDKCceM" : {
"pin" : "kPllwcoaob",
"say": "Hello"
}
}
}
}
}
what I need is to find for all the 'pin' keys, and get their values, to put them into an array.
Exactly, I need to have an array like this:
['6K3jP5vLyN', 'hnPKh7ywvT', 'xWwaNNE2XG', 'vMU1mKbZAi', 'qXJCQREATD', 'o5D8S8Lvtb', '9zDuHcw6qH', 'kPllwcoaob']
I have tried:
const array = [];
function iter(obj){
for(key in obj){
if(obj.pin)
array.push(obj.pin);
if(obj[key]!==null && typeof obj[key]==="object"){
iter(obj[key]);
}
}
}
iter(obj);
But I get the values of each key twice. Is there some improved way to do this?
You can use a recursive method to flatten the nested object to it's leaf values.
Option 1 - the value is the only property on the leaf (original answer before question updated)
The method extracts the current values to an array using Object.values(). It iterates the array with Array.map(), and flattens any value which is an object. The result of each run is spread into Array.concat() to flatten the nested arrays.
const data = {"PINS":{"2017":{"Nov-2017":{"VJkRWX7pTSl_5w1Np":{"pin":"6K3jP5vLyN"},"MsdsXiO9G9mwM3Qa":{"pin":"hnPKh7ywvT"}},"Dec-2017":{"Mm35Gjb-nY0k2TV":{"pin":"xWwaNNE2XG"},"WzajCLEJmJHmzg0":{"pin":"vMU1mKbZAi"}}},"2018":{"Jan-2018":{"Wf8E1unVaOh03a43":{"pin":"qXJCQREATD"},"JZqP8fVCLSja6J82v":{"pin":"o5D8S8Lvtb"}},"Feb-2018":{"lMMAKNLy8jtnnXAN":{"pin":"9zDuHcw6qH"},"e9EV3HDKCceM":{"pin":"kPllwcoaob"}}}}};
const flattenObj = (obj) =>
[].concat(...Object.values(obj).map((o) => typeof o === 'object' ? flattenObj(o) : o));
const result = flattenObj(data);
console.log(result);
Option 2 - the value is not the only property on the leaf
If your data contains other keys, this variant uses Object.entries() to extract a specific key:
const data = {"PINS":{"2017":{"Nov-2017":{"VJkRWX7pTSl_5w1Np":{"pin":"6K3jP5vLyN","say":"Hello"},"MsdsXiO9G9mwM3Qa":{"pin":"hnPKh7ywvT","say":"Hello"}},"Dec-2017":{"Mm35Gjb-nY0k2TV":{"pin":"xWwaNNE2XG","say":"Hello"},"WzajCLEJmJHmzg0":{"pin":"vMU1mKbZAi","say":"Hello"}}},"2018":{"Jan-2018":{"Wf8E1unVaOh03a43":{"pin":"qXJCQREATD","say":"Hello"},"JZqP8fVCLSja6J82v":{"pin":"o5D8S8Lvtb","say":"Hello"}},"Feb-2018":{"lMMAKNLy8jtnnXAN":{"pin":"9zDuHcw6qH","say":"Hello"},"e9EV3HDKCceM":{"pin":"kPllwcoaob","say":"Hello"}}}}};
const flattenObjKey = (obj, key) =>
[].concat(...Object.entries(obj)
.map(([k, v]) => typeof v === 'object' ?
flattenObjKey(v, key) : (k === key ? v : [])
));
const result = flattenObjKey(data, 'pin');
console.log(result);
It looks like your data is consistently structured, so this is fairly simple.
const pins = [];
for (let year in pins) {
for (let month in year) {
for (let key in months) {
pins.push(key.pin);
}
}
}
If it's not consistently structured, you'll need to extract a recursive solution that looks for pin keys.
Hi i have something like:
var obj = {
level1 : {
level2 : 'value'
}
};
Also another object:
var returnData = {
value: "level1.level2",
anotherThing: "level1"
};
I want to loop through all the keys from the returnData object and get those values from the obj object. I have this but can't get the wanted value for the key value in returnData:
var dataToreturn = [];
$.each(returnData, function(k, v) {
dataToreturn[k] = obj[v];
});
So the final result would be:
dataToreturn[value] = 'value';
dataToreturn[anotherThing] = {
level2 : 'value'
};
https://jsfiddle.net/3u4vxwc5/8/
You can use both forEach() and reduce(). forEach to loop object keys and then split() each value at . and then use reduce() to loop those values and add to array.
var obj = {
level1: {
level2: 'value'
}
};
var returnData = {
value: "level1.level2",
anotherThing: "level1"
};
var dataToreturn = [];
Object.keys(returnData).forEach(function(e) {
var keys = returnData[e].split('.')
keys.reduce(function(r, e, i) {
if (keys[i + 1] && r[e]) return r[e]
else if (r[e]) dataToreturn.push(r[e])
return r;
}, obj)
})
console.log(dataToreturn)
var obj = {
level1 : {
level2 : 'value'
}
};
var returnData = {
value: "level1.level2",
anotherThing: "level1"
};
Object.keys(returnData).forEach(key=>returnData[key]=returnData[key].split(".").reduce((val,key)=>val[key],obj)||returnData[key]);
console.log(returnData);
Iterate over all keys of return Data and reduce it to a value.