This question already has answers here:
Add a property to a JavaScript object using a variable as the name? [duplicate]
(14 answers)
Closed 3 years ago.
Seeking the below result with dynamic list of object using javascript. Defined approach getting me undefined index of value.
Javascript Code
var obj = {};
var obj_ = {
"clist_1": "abc",
"clist_2": "def",
"branch_1": "efg"
}
for (let key in obj_) {
if (key.includes("clist_")) {
let num = key.replace(/^\D+/g, '');
obj[num] = obj_.key;
}
}
console.log(obj)
Desired Result
{
"1": "abc",
"2": "def"
}
You can use bracket notation. You need to do obj_[key] and not obj_.key.
var obj = {};
var obj_ = {
"clist_1": "abc",
"clist_2": "def",
"branch_1": "efg"
}
for (let key in obj_) {
if (key.includes("clist_")) {
let num = key.replace(/^\D+/g, '');
obj[num] = obj_[key];
}
}
console.log(obj)
You need a property accessor in bracket notation for the key.
obj[num] = obj_[key];
// ^^^^^
Then you could use startsWith instead of includes for checking the starting part of a string.
var obj = {};
var obj_ = {
"clist_1": "abc",
"clist_2": "def",
"branch_1": "efg"
}
for (let key in obj_) {
if (key.startsWith("clist_")) {
let num = key.replace(/^\D+/g, '');
obj[num] = obj_[key];
}
}
console.log(obj);
Alternative chain way:
var obj = {};
var obj_ = {
"clist_1": "abc",
"clist_2": "def",
"branch_1": "efg"
};
Object.keys(obj_)
.map(key=>key.replace(/^\D+/g, ''))
.map(key=>obj[key]=obj_[key]);
console.log(obj);
You can do:
const obj_ = {"clist_1": "abc","clist_2": "def","branch_1": "efg"};
const obj = Object.keys(obj_)
.filter(k => k.startsWith('clist_'))
.reduce((a, c) => (a[c.match(/\d+/g)] = obj_[c], a), {});
console.log(obj);
Related
This question already has answers here:
Why does Array.prototype.push return the new length instead of something more useful?
(6 answers)
Closed 12 months ago.
I have a large Object containing addresses and numbers.
{
'0x2bac18ad331A3137AbEC3a029dBb3A6cC25835ea': 1,
'0x22Bf3f4EA7862739024C122aDDd2FB2981c076a7': 3,
'0x9E6E8b584F26503C84661674dCD7821099c8a51d': 1,
'0x37D74ca0F842817C6FC4Ea267cF2d49DEa0C06a8': 1,
'0xDf92913902087aD0Bfac39659B60CebE1100595a': 1
// ...
}
and I try to swap key/values and store all addresses with the same number value in an Array, thinking of something like this:
var newObj = {
"1": [addr1, addr2, addr3],
"2": [addr1, addr2, addr3],
"3": [addr1, addr2, addr3]
//...
}
I found a way to swap like this:
function swaptoArray(json){
var ret = {};
for(var key in json){
ret[json[key]] = key;
}
return ret;
}
but I am having trouble making the value-part an Array containing many addresses.
I tried this, but don't understand the wrong result. Any hints?
function swaptoArray(json){
var ret = {};
var newArray = [];
for(var key in json){
ret[json[key]] = newArray.push(key);
}
return ret;
}
Result:
{ '1': 5, '3': 2 }
Here's a solution using Object.entries:
const obj = {
'0x2bac18ad331A3137AbEC3a029dBb3A6cC25835ea': 1,
'0x22Bf3f4EA7862739024C122aDDd2FB2981c076a7': 3,
'0x9E6E8b584F26503C84661674dCD7821099c8a51d': 1,
'0x37D74ca0F842817C6FC4Ea267cF2d49DEa0C06a8': 1,
'0xDf92913902087aD0Bfac39659B60CebE1100595a': 1
}
const objArr = Object.entries(obj)
function getArray(key) {
let ret = []
objArr.forEach(item => {
if(item[1] === key) ret.push(item[0])
})
return ret
}
function swaptoArray(json) {
let ret = {}
for (let key in json) {
const newKey = json[key]
ret[newKey] = getArray(newKey)
}
return ret
}
console.log(swaptoArray(obj))
You need an array as result for every value as key for the result.
function group(object) {
const result = {};
for (const key in object) (result[data[key]] ??= []).push(key);
return result;
}
const data = {
'0x2bac18ad331A3137AbEC3a029dBb3A6cC25835ea': 1,
'0x22Bf3f4EA7862739024C122aDDd2FB2981c076a7': 3,
'0x9E6E8b584F26503C84661674dCD7821099c8a51d': 1,
'0x37D74ca0F842817C6FC4Ea267cF2d49DEa0C06a8': 1,
'0xDf92913902087aD0Bfac39659B60CebE1100595a': 1
}
console.log(group(data));
This question already has answers here:
Accessing nested JavaScript objects and arrays by string path
(44 answers)
Closed 7 years ago.
I'm temporarily stuck with what appears to be a very simple JavaScript problem, but maybe I'm just missing the right search keywords!
Say we have an object
var r = { a:1, b: {b1:11, b2: 99}};
There are several ways to access the 99:
r.b.b2
r['b']['b2']
What I want is to be able to define a string
var s = "b.b2";
and then access the 99 using
r.s or r[s] //(which of course won't work)
One way is to write a function for it that splits the string on dot and maybe recursively/iteratively gets the property. But is there any simpler/more efficient way? Anything useful in any of the jQuery APIs here?
Here's a naive function I wrote a while ago, but it works for basic object properties:
function getDescendantProp(obj, desc) {
var arr = desc.split(".");
while(arr.length && (obj = obj[arr.shift()]));
return obj;
}
console.log(getDescendantProp(r, "b.b2"));
//-> 99
Although there are answers that extend this to "allow" array index access, that's not really necessary as you can just specify numerical indexes using dot notation with this method:
getDescendantProp({ a: [ 1, 2, 3 ] }, 'a.2');
//-> 3
split and reduce while passing the object as the initalValue
Update
(thanks to comment posted by TeChn4K)
With ES6 syntax, it is even shorter
var r = { a:1, b: {b1:11, b2: 99}};
var s = "b.b2";
var value = s.split('.').reduce((a, b) => a[b], r);
console.log(value);
Old version
var r = { a:1, b: {b1:11, b2: 99}};
var s = "b.b2";
var value = s.split('.').reduce(function(a, b) {
return a[b];
}, r);
console.log(value);
You can use lodash get() and set() methods.
Getting
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.get(object, 'a[0].b.c');
// → 3
Setting
var object = { 'a': [{ 'b': { 'c': 3 } }] };
_.set(object, 'a[0].b.c', 4);
console.log(object.a[0].b.c);
// → 4
If it's possible in your scenario that you could put the entire array variable you're after into a string you could use the eval() function.
var r = { a:1, b: {b1:11, b2: 99}};
var s = "r.b.b2";
alert(eval(s)); // 99
I can feel people reeling in horror
Extending #JohnB's answer, I added a setter value as well. Check out the plunkr at
http://plnkr.co/edit/lo0thC?p=preview
function getSetDescendantProp(obj, desc, value) {
var arr = desc ? desc.split(".") : [];
while (arr.length && obj) {
var comp = arr.shift();
var match = new RegExp("(.+)\\[([0-9]*)\\]").exec(comp);
// handle arrays
if ((match !== null) && (match.length == 3)) {
var arrayData = {
arrName: match[1],
arrIndex: match[2]
};
if (obj[arrayData.arrName] !== undefined) {
if (typeof value !== 'undefined' && arr.length === 0) {
obj[arrayData.arrName][arrayData.arrIndex] = value;
}
obj = obj[arrayData.arrName][arrayData.arrIndex];
} else {
obj = undefined;
}
continue;
}
// handle regular things
if (typeof value !== 'undefined') {
if (obj[comp] === undefined) {
obj[comp] = {};
}
if (arr.length === 0) {
obj[comp] = value;
}
}
obj = obj[comp];
}
return obj;
}
This is the simplest i could do:
var accessProperties = function(object, string){
var explodedString = string.split('.');
for (i = 0, l = explodedString.length; i<l; i++){
object = object[explodedString[i]];
}
return object;
}
var r = { a:1, b: {b1:11, b2: 99}};
var s = "b.b2";
var o = accessProperties(r, s);
alert(o);//99
you could also do
var s = "['b'].b2";
var num = eval('r'+s);
Here is an extension of Andy E's code, that recurses into arrays and returns all values:
function GetDescendantProps(target, pathString) {
var arr = pathString.split(".");
while(arr.length && (target = target[arr.shift()])){
if (arr.length && target.length && target.forEach) { // handle arrays
var remainder = arr.join('.');
var results = [];
for (var i = 0; i < target.length; i++){
var x = this.GetDescendantProps(target[i], remainder);
if (x) results = results.concat(x);
}
return results;
}
}
return (target) ? [target] : undefined; //single result, wrap in array for consistency
}
So given this target:
var t =
{a:
{b: [
{'c':'x'},
{'not me':'y'},
{'c':'z'}
]
}
};
We get:
GetDescendantProps(t, "a.b.c") === ["x", "z"]; // true
I don't know a supported jQuery API function but I have this function:
var ret = data; // Your object
var childexpr = "b.b2"; // Your expression
if (childexpr != '') {
var childs = childexpr.split('.');
var i;
for (i = 0; i < childs.length && ret != undefined; i++) {
ret = ret[childs[i]];
}
}
return ret;
I've extended Andy E's answer, so that it can also handle arrays:
function getDescendantProp(obj, desc) {
var arr = desc.split(".");
//while (arr.length && (obj = obj[arr.shift()]));
while (arr.length && obj) {
var comp = arr.shift();
var match = new RegExp("(.+)\\[([0-9]*)\\]").exec(comp);
if ((match !== null) && (match.length == 3)) {
var arrayData = { arrName: match[1], arrIndex: match[2] };
if (obj[arrayData.arrName] != undefined) {
obj = obj[arrayData.arrName][arrayData.arrIndex];
} else {
obj = undefined;
}
} else {
obj = obj[comp]
}
}
return obj;
}
There are probably more efficient ways to do the Regex, but it's compact.
You can now do stuff like:
var model = {
"m1": {
"Id": "22345",
"People": [
{ "Name": "John", "Numbers": ["07263", "17236", "1223"] },
{ "Name": "Jenny", "Numbers": ["2", "3", "6"] },
{ "Name": "Bob", "Numbers": ["12", "3333", "4444"] }
]
}
}
// Should give you "6"
var x = getDescendantProp(model, "m1.People[1].Numbers[2]");
Performance tests for Andy E's, Jason More's, and my own solution are available at http://jsperf.com/propertyaccessor. Please feel free to run tests using your own browser to add to the data collected.
The prognosis is clear, Andy E's solution is the fastest by far!
For anyone interested, here is the code for my solution to the original question.
function propertyAccessor(object, keys, array) {
/*
Retrieve an object property with a dot notation string.
#param {Object} object Object to access.
#param {String} keys Property to access using 0 or more dots for notation.
#param {Object} [array] Optional array of non-dot notation strings to use instead of keys.
#return {*}
*/
array = array || keys.split('.')
if (array.length > 1) {
// recurse by calling self
return propertyAccessor(object[array.shift()], null, array)
} else {
return object[array]
}
}
Short answer: No, there is no native .access function like you want it. As you correctly mentioned, you would have to define your own function which splits the string and loops/checks over its parts.
Of course, what you always can do (even if its considered bad practice) is to use eval().
Like
var s = 'b.b2';
eval('r.' + s); // 99
Here is a a little better way then #andy's answer, where the obj (context) is optional, it falls back to window if not provided..
function getDescendantProp(desc, obj) {
obj = obj || window;
var arr = desc.split(".");
while (arr.length && (obj = obj[arr.shift()]));
return obj;
};
I have this array:
myArray = ["AAA","BBB",...,"ZZZ"];
I want to convert it to an array of objects. Something like this:
myArray = [
{
"Id": "111",
"Value": "AAA"
},
....
{
"Id": "111",
"Value": "ZZZ"
},
];
I've tried to use the map method like this:
myArray.map(str => {
let obj = {};
obj['Id'] = '111';
obj['Value'] = str;
});
But console.log(myArray) outputs this:
undefined
You need to return a result from the mapper function.
let myNewArray = myArray.map( str => {
let obj = {};
obj['Id'] = '111' ;
obj['Value'] = str ;
return obj;
});
// or
let myNewArray = myArray.map( str => ({Id:111,Value:str}) );
// parenthesis are needed to remove the ambiguity with `{}`
console.log(myNewArray);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map#Using_map_to_reformat_objects_in_an_array
Here is the clean ES6 one liner version using Array#map
const data = myArray = ["AAA","BBB","ZZZ"];
let result = data.map(e => ({'Id': '111', 'Value': e}));
console.log(result);
You need to return the result into a new variable, or your existing one, as map create a new array and doesn't change the one you are iterating over.
const myArrayOfObjects = myArray.map( str => {
let obj = {};
obj['Id'] = '111' ;
obj['Value'] = str ;
return obj;
});
This question already has answers here:
Accessing nested JavaScript objects and arrays by string path
(44 answers)
Closed 4 years ago.
Suppose I have an object
var obj = {
subObj : {
value : 1
}
};
Is there any way to get obj.subObj.value using a complex property-name string that goes to sub objects?
Example (that doesn't work)
var attr = "subObj.value";
return obj[attr];
No you can't.
You can split and loop over every attr.
var obj = {
subObj : {
value : 1
}
};
var attr = "subObj.value";
var result = obj;
attr.split('.').forEach((c) => result = result[c]);
console.log(result);
Or you can use reduce:
var obj = {
subObj : {
value : 1
}
};
var attr = "subObj.value";
var result = attr.split('.').reduce((a, c) => a[c], obj);
console.log(result);
There is no notation to do this in JavaScript but you could use something like this:
var obj = {
subObj : {
value : 1
}
};
var attr = "subObj.value";
var result = attr.split(".").reduce((a, c) => a[c], obj);
console.log(result)
I have an array of objects like this:
[
{ "key": "fruit", "value": "apple" },
{ "key": "color", "value": "red" },
{ "key": "location", "value": "garden" }
]
I need to convert it to the following format:
[
{ "fruit": "apple" },
{ "color": "red" },
{ "location": "garden" }
]
How can this be done using JavaScript?
You can use .map
var data = [
{"key":"fruit","value":"apple"},
{"key":"color","value":"red"},
{"key":"location","value":"garden"}
];
var result = data.map(function (e) {
var element = {};
element[e.key] = e.value;
return element;
});
console.log(result);
also if you use ES2015 you can do it like this
var result = data.map((e) => {
return {[e.key]: e.value};
});
Example
Using an arrow function, with the data called arr
arr.map(e => {
var o = {};
o[e.key] = e.value;
return o;
});
This generates a new Array and does not modify the original
It can be simplified down to one line as
arr.map(e => ({[e.key]: e.value}));
If you can't assume arrow function support yet, you would write this longhand
arr.map(function (e) {
var o = {};
o[e.key] = e.value;
return o;
});
Using map (as suggested in other answers) or the following will do what you want...
var data = [{"key":"fruit","value":"apple"},{"key":"color","value":"red"},{"key":"location","value":"garden"}];
var obj = {};
for(var i = 0; i < data.length; i++) {
obj[data[i]["key"]] = data[i]["value"];
}
In Javascript, obj.property and obj['property'] return same things.
obj['property'] is more flexible because the key 'property' could be a string with some space :
obj['pro per ty'] // work
obj.pro per ty // not work
or
var a = 'property';
obj.a == obj.property // => false
obj[a] == obj.property // => true
So you could try that.
var data = [{"key":"fruit","value":"apple"},{"key":"color","value":"red"},{"key":"location","value":"garden"}]
var new_data = [];
var data_length = data.length; // just a little optimisation for-loop
for (var i = 0; i < data_length; i++) {
var item = data[i]; // to have a vision close of foreach-loop (foreach item of collection)
new_data[i] = {};
new_data[i][item.key] = item.value;
}
console.log(new_data);
// [{"fruit":"apple"},{"color":"red"},{"location":"garden"}]
What you currently have is an array of object, each having two attributes, key and value. If you are not aware of map, you can always run a forEach loop on this array and rearrange the data. Try something like below:
function() {
var newArray = [];
oldArray.forEach(function(x){
var obj= {};
obj[x.key] = x.value;
newArray.push(obj);
});
console.log(newArray);
}
here oldArray is your original data