I have an object with named keys like this
{
'name[first]': 'john',
'name[last]': 'doe'
}
that I want to convert to:
{
'name' : {
'first' : 'john',
'last' : 'doe'
}
}
Any idea on an elegent way to do this?
You can use reduce() to return obj and regular expression to split key.
var obj = {
'name[first]': 'john',
'name[last]': 'doe'
}
var result = Object.keys(obj).reduce(function(r, e) {
var key = e.split(/\[(.*?)\]/)
if (!r[key[0]]) r[key[0]] = {}
r[key[0]][key[1]] = obj[e]
return r;
}, {})
console.log(result)
For nested key structure you could again use reduce but with different approach to keys but then you face problem of deep merge of object and for that you can use lodash.
var obj = {
'name[first[foo]]': 'john',
'name[last]': 'doe',
'name[last[foo[bar]]]': 'doe'
}
var result = Object.keys(obj).reduce(function(r, e) {
var key = e.replace(/\[/g, '.').replace(/\]/g, '').split('.')
var o = {}
key.reduce(function(re, el, i) {
return i != key.length - 1 ? re[el] = {} : re[el] = obj[e]
}, o)
r = _.merge(r, o)
return r;
}, {})
console.log(JSON.stringify(result, 0, 4))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>
Using a for..in loop and constructing a new object:
var obj = {
'name[first]': 'john',
'name[last]': 'doe'
};
var newObj = {}
for (var key in obj) {
var parts = key.split(/\[|\]/);
if(!newObj.hasOwnProperty(parts[0]))
newObj[parts[0]] = {};
newObj[parts[0]][parts[1]] = obj[key];
}
console.log(newObj);
The solution using Object.keys, Array.prototytpe.reduce and String.prototype.match functions:
var obj = {'name[first]': 'john', 'name[last]': 'doe'};
var result = Object.keys(obj).reduce(function (o, key) {
var parts = key.match(/^(\w+)\[(\w+)\]$/);
if (!o[parts[1]]) {
o[parts[1]] = {};
}
o[parts[1]][parts[2]] = obj[key];
return o;
}, {});
console.log(result);
var obj = {
'name[first]': 'john',
'name[last]': 'doe'
}
var newObj = {};
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
var keys = property.match(/(\w+)/g);
if (keys && keys.length == 2) {
newObj[keys[0]] = newObj[keys[0]] || {};
newObj[keys[0]][keys[1]] = obj[property];
}
}
}
console.log(newObj);
You can try the following:
var obj = {
'name[first]': 'john',
'name[last]': 'doe'
}
var result = Object.keys(obj).reduce(function(newObj, prop) {
var key = prop.split(/\[|\]/)[1];
newObj[key] = obj[prop];
return newObj;
}, {})
console.log(result);
Related
I have an array of object, something like this:
array = [
{
'propertyName1': 'name1',
'propertyValue1': 'value1',
'propertyName2': 'name2',
'propertyValue2': 'value2',
'propertyName3': 'name3',
'propertyValue3': 'value3',
'propertyName4': 'name4',
'propertyValue4': 'value4',
},
{
'propertyName1': 'name10',
'propertyValue1': 'value10',
'propertyName2': 'name22',
'propertyValue2': 'value22',
'propertyName3': 'name33',
'propertyValue3': 'value33',
'propertyName4': null,
'propertyValue4': null,
}
]
I want to get the first value as a key and the second value as a value in a new object, something like this result:
{
name1: "value1"
name10: "value10"
name2: "value2"
name22: "value22"
name3: "value3"
name33: "value33"
name4: "value4"
null: null
}
but I don't want to show the property with the value null, so I tried:
ngOnInit() {
let obj = {};
this.array.forEach((element: any) => {
obj = {
...obj,
[element.propertyName1]: element.propertyValue1,
[element.propertyName2]: element.propertyValue2,
[element.propertyName3]: element.propertyValue3,
[element.propertyName4]: element.propertyValue4}
}
);
console.log(obj);
}
See the code here:
Stackblitz
Just delete the null entry after
this.array.forEach((element: any) => {
obj = {
...obj,
[element.propertyName1]: element.propertyValue1,
[element.propertyName2]: element.propertyValue2,
[element.propertyName3]: element.propertyValue3,
[element.propertyName4]: element.propertyValue4,
};
});
delete obj['null'];
https://stackblitz.com/edit/angular-ivy-gaqes8?file=src/app/app.component.ts
You can spread all the values in a single array and check if the property is null while looping over:
ngOnInit() {
const valuesArray = [ //Array containing all the values
...Object.values(this.array[0]),
...Object.values(this.array[1]),
];
let obj = {};
for (let i = 0; i < valuesArray.length; i = i + 2) {
if (valuesArray[i + 1] !== null) {
obj[valuesArray[i]] = valuesArray[i + 1]; //Only copy when it is not null
}
}
console.log(obj);
}
If your first array also might contain null values and you want to exclude them you can use this if condition instead of the one above:
if (valuesArray[i + 1] !== null && valuesArray[i] !== null )
const data = [{"propertyName1":"name1","propertyValue1":"value1","propertyName2":"name2","propertyValue2":"value2","propertyName3":"name3","propertyValue3":"value3","propertyName4":"name4","propertyValue4":"value4"},{"propertyName1":"name10","propertyValue1":"value10","propertyName2":"name22","propertyValue2":"value22","propertyName3":"name33","propertyValue3":"value33","propertyName4":null,"propertyValue4":null}]
let r = {}
// get maximum number of keys that may need to be iterated over
let n = data.map(o=>Object.keys(o).length).reduce((a,c)=>Math.max(a,c))
for(let i=1; i<=n; i++) {
data.forEach(o=> {
let x = o[`propertyName${i}`]
let y = o[`propertyValue${i}`]
if (x && y) r[x] = y
})
}
console.log(r)
I would like to merge an array with another array. The only catch is that each array is within an object.
Intuitively I tried {...arrObj, ...newArrObj} however this leads newArrObj overwriting items in the arrObj.
const array = ['an', 'array'];
const newArray = [, , 'new', 'ehrray'];
const obj = {
key: { ...array
}
};
const newObj = {
key: { ...newArray
}
};
const merged = { ...obj,
...newObj
};
console.log(merged);
I would expect merged to be:
{
"key": {
"0": "an",
"1": "array",
"2": "new",
"3": "ehrray"
}
}
but receive
{
"key": {
"2": "new",
"3": "ehrray"
}
}
This might be useful
const a0 = ['1', '2', undefined , undefined, '5', '6', '7'];
const a1 = [undefined, undefined, '3', '4'];
function merge(a, b) {
return a.map(function(v,i){ return v?v:b[i]});
}
console.log(a0 > a1?merge(a0, a1):merge(a1, a0));
I wanted to updated that I ended up going with a recursive merge to get the nested object containing an array merged.
const array = ['an', 'array'];
const newArray = [, , 'new', 'ehrray'];
const obj = {
key: { ...array
}
};
const newObj = {
key: { ...newArray
}
};
const merge = (obj1, obj2) => {
const recursiveMerge = (obj, entries) => {
for (const [key, value] of entries) {
if (typeof value === "object") {
obj[key] = obj[key] ? { ...obj[key]
} : {};
recursiveMerge(obj[key], Object.entries(value))
} else {
obj[key] = value;
}
}
return obj;
}
return recursiveMerge(obj1, Object.entries(obj2))
}
console.log(merge(obj, newObj));
The idea is that there are unset values with only a few set. eg. const newArray = new Array(4); newArray[2] = 'new';
{ value: null }, even { value: undefined } is not the same thing as { foo: 42 } with no value at all. That's the reason that in your example "an" and "array" are overwritten with the nulls from the newArray.
This particular example you can solve by swapping the order in which you add the arrays to the result, but as soon as both arrays contain null-values there is no way to do it with spread-syntax / Object.assign alone. You have to implement the behaviour:
const array = new Array('an', 'array', null, null, "and", "more", "from", "array");
const newArray = new Array(null, null, 'new', 'ehrray');
function merge(a, b) {
const result = [];
for (let i = 0; i < a.length || i < b.length; ++i) {
result[i] = b[i] == null ? a[i] : b[i];
}
return result;
}
console.log(merge(array, newArray));
A little bit stuck on the following scenario.
I have three arrays, and using the arrays would like to create a new object.
var fields = ['firstName', 'lastName', 'email'],
oldVals = ['John', 'Doe', 'doe#mail.com'],
newVals = ['Jo','Do','jo#mail.com'];
The new object should be as :
{
"firstName": {
"oldValue": "John",
"newValue": "Jo"
},
"lastName": {
"oldValue": "John",
"newValue": "Do"
},
"email": {
"oldValue": "doe#mail.com",
"newValue": "jo#mail.com"
}
}
Thanks in advance.
// first check that your arrays are actually all the same length. Then...
var obj = {};
for(var i=0;i<fields.length;i++) {
obj[fields[i]] = {
oldValue: oldVals[i],
newValue: newVals[i]
}
}
Assuming lengths are same, Using reduce function of array
fields.reduce(function(res,x,index){
res[x] = {
oldValue:oldVals[index],
newValue:newVals[index]
}
return res;
},{});
A proposal with Array#forEach and some arrays for dynamic generation of the object.
var fields = ['firstName', 'lastName', 'email'],
oldVals = ['John', 'Doe', 'doe#mail.com'],
newVals = ['Jo', 'Do', 'jo#mail.com'],
object = function (array, keys1, keys2) {
var r = {};
keys1.forEach(function (k1, i) {
r[k1] = r[k1] || {};
keys2.forEach(function (k2, j) {
r[k1][k2] = array[j][i];
});
});
return r;
}([oldVals, newVals], fields, ['oldVals', 'newVals']);
document.write('<pre>' + JSON.stringify(object, 0, 4) + '</pre>');
A property can be created dynamically thus:
objectName[propertyVariable] = valueVariable;
So in the present case something like this would do the trick.
var object1 = {};
object1[fields[0]] = { oldValue: oldVals[0], newValue: newVals[0] }
I wanted to add this solution , which will encapsulate it in a method, like this :
var fields = ['firstName', 'lastName', 'email'],
oldVals = ['John', 'Doe', 'doe#mail.com'],
newVals = ['Jo','Do','jo#mail.com'];
function createCustomObj(fields , oldVals, newVals){
var obj={};
fields.forEach( function(f, i){
obj[f]={};
obj[f]['oldValue']= oldVals[i];
obj[f]['newValue']= newVals[i];
});
return obj;
};
console.log(createCustomObj(fields, oldVals, newVals));
https://jsfiddle.net/x54b0rhk/
I've looped through an document.form.element the names are constructed into an array name like so:
Current output
Some of the names of they keys are like so in JSON:
{
data[name]: "foo",
data[address]: "baz drive",
data[city]: "Dallas",
data[state]: "Texas",
data[phone]: "555-1212"
}
Desired output
Is there a way to convert it to this with Pure JavaScript (and without frameworks like jQuery) without using eval?:
{
data: {
name: "foo",
address: "baz drive",
city: "Dallas",
state: "Texas",
phone: "555-1212"
}
}
What have i tried so far
<script type="javascript">
var o = {
data[name]: "foo",
data[address]: "baz drive",
data[city]: "Dallas",
data[state]: "Texas",
data[phone]: "555-1212"
}
var temp = [];
for (key in o) {
temp[JSON.parse(key)] = o;
}
</script>
Fiddle is here: http://jsfiddle.net/chrisjlee/medbzv9a/
Or is this not totally possible?
Do like
var o = {
"data[name]": "foo",
"data[address]": "baz drive",
"data[city]": "Dallas",
"data[state]": "Texas",
"data[phone]": "555-1212"
};
o.data = {};
for (key in o) {
var index = key.match(/[^[\]]+(?=])/g);
if(index) {
o.data[index] = o[key];
delete(o[key]);
}
}
console.log(o);
Here is a sample fiddle.
The following function should fix the object. It will be executed recursively and it can handle arrays too.
var fixKeys = function(obj) {
if (typeof(obj) != "object")
return obj;
if (Object.prototype.toString.call(obj) == "[object Array]")
return obj.map(arguments.callee);
var newObj = {};
for (var key in obj) {
if (!obj.hasOwnProperty(key))
continue;
var m = /^(\w+)\[(\w+)\]$/.exec(key);
if (m) {
newObj[m[1]] = newObj[m[1]] || {};
newObj[m[1]][m[2]] = arguments.callee(obj[key]);
} else {
newObj[key] = arguments.callee(obj[key]);
}
}
return newObj;
};
Fiddle
And here's an even better version, which can handle data of this type:
var o = {
"data[name]": "foo",
"data[address][street]": "baz drive",
"data[address][city]": "Dallas",
"data[address][state]": "Texas",
"data[phone]": "555-1212",
someArray: [
{"test[a]": 42},
42
]
};
Just in case you need it:
var fixKeys = function(obj) {
if (typeof(obj) != "object")
return obj;
if (Object.prototype.toString.call(obj) == "[object Array]")
return obj.map(arguments.callee);
var newObj = {};
for (var key in obj) {
if (!obj.hasOwnProperty(key))
continue;
var m = /^(\w+)(?:\[\w+\])+$/.exec(key);
if (m) {
var subKey = key.substr(m[1].length);
var subObj = newObj[m[1]] = newObj[m[1]] || {};
while (m = /^\[(\w+)\]\[/.exec(subKey)) {
subObj = subObj[m[1]] = subObj[m[1]] || {};
subKey = subKey.substr(m[0].length - 1);
}
m = /^\[(\w+)\]$/.exec(subKey);
subObj[m[1]] = arguments.callee(obj[key]);
} else {
newObj[key] = arguments.callee(obj[key]);
}
}
return newObj;
};
Fiddle
I have a JavaScript object like
var obj = {
key1: 'value1',
key2: 'value2',
key3: 'value3',
key4: 'value4'
}
How can I get the length and list of keys in this object?
var obj = {
key1: 'value1',
key2: 'value2',
key3: 'value3',
key4: 'value4'
}
var keys = Object.keys(obj);
console.log('obj contains ' + keys.length + ' keys: '+ keys);
It's supported on most major browsers now.
var obj = {
key1: 'value1',
key2: 'value2',
key3: 'value3',
key4: 'value4'
};
var keys = [];
for (var k in obj) keys.push(k);
console.log("total " + keys.length + " keys: " + keys);
Underscore.js makes the transformation pretty clean:
var keys = _.map(x, function(v, k) { return k; });
Edit: I missed that you can do this too:
var keys = _.keys(x);
If you only want the keys which are specific to that particular object and not any derived prototype properties:
function getKeys(obj) {
var r = []
for (var k in obj) {
if (!obj.hasOwnProperty(k))
continue
r.push(k)
}
return r
}
e.g:
var keys = getKeys({'eggs': null, 'spam': true})
var length = keys.length // access the `length` property as usual for arrays
var keys = new Array();
for(var key in obj)
{
keys[keys.length] = key;
}
var keyLength = keys.length;
to access any value from the object, you can use obj[key];
obj = {'a':'c','b':'d'}
You can try:
[index for (index in obj)]
this will return:
['a','b']
to get the list of keys
or
[obj[index] for (index in obj)]
to get the values
Anurags answer is basically correct.
But to support Object.keys(obj) in older browsers as well you can use the code below that is copied from
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
. It adds the Object.keys(obj) method if it's not available from the browser.
if (!Object.keys) {
Object.keys = (function() {
'use strict';
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function(obj) {
if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
throw new TypeError('Object.keys called on non-object');
}
var result = [], prop, i;
for (prop in obj) {
if (hasOwnProperty.call(obj, prop)) {
result.push(prop);
}
}
if (hasDontEnumBug) {
for (i = 0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) {
result.push(dontEnums[i]);
}
}
}
return result;
};
}());
}
Use Object.keys()... it's the way to go.
Full documentation is available on the MDN site linked below:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
Note that in coffeescript this can be accomplished in all browsers and node as
k for k of obj
and thus
(1 for _ of obj).length
Recursive solution for browsers that support ECMAScript 5:
var getObjectKeys = function(obj) {
var keys = Object.keys(obj);
var length = keys.length;
if (length !== 0) {
for (var i = 0; i < length; i++) {
if (typeof obj[keys[i]] === 'object') {
keys[keys[i]] = getObjectKeys(obj[keys[i]]);
}
}
}
return keys;
};
var obj = {
key1: 'value1',
key2: 'value2',
key3: 'value3',
key4: 'value4'
}
console.log(Object.keys(obj));
console.log(Object.keys(obj).length)
If you decide to use Underscore.js you better do
var obj = {
key1: 'value1',
key2: 'value2',
key3: 'value3',
key4: 'value4'
}
var keys = [];
_.each( obj, function( val, key ) {
keys.push(key);
});
console.log(keys.lenth, keys);
In JavaScript, an object is a standalone entity, with properties and type.
For fetching values from Object in form of array:
Object.values(obj) // obj is object name that you used
Result -> ["value1", "value2", "value3", "value4"]
For fetching keys from Object in form of array:
Object.keys(obj) // obj is object name that you used
Result -> ["key1", "key2", "key3", "key4"]
As both functions are returning array you can get the length of keys or value by using length property. For instance - Object.values(obj).length or Object.keys(obj).length
Modern browsers do support:
var obj = {
key1: 'value1',
key2: 'value2',
key3: 'value3',
key4: 'value4'
}
console.log(Object.keys(obj));
// we can also get values
console.log(Object.values(obj));
For a comma-delineated string listing the keys of a JSON Object, try the following:
function listKeys(jObj){
var keyString = '';
for(var k in jObj){
keyString+=(','+k);
}
return keyString.slice(1);
}
/* listKeys({'a' : 'foo', 'b' : 'foo', 'c' : 'foo'}) -> 'a,b,c' */
Using ES6,
you can use forEach to iterate over the Keys of an Object.
To get all the keys you can use Object.keys which returns all the keys in an Object
Object.keys(obj).forEach(function(keyValue, index, map) {
console.log(keyValue);
});
Short hand of the above snippet would be, which only takes one parameter
Object.keys(obj).forEach(function(keyValue) {
console.log(keyValue);
});
if(props.userType){
var data = []
Object.keys(props.userType).map(i=>{
data.push(props.userType[i])
})
setService(data)
}
using slice, apply and join method.
var print = Array.prototype.slice.apply( obj );
alert('length='+print.length+' list'+print.join());
Here is solution for getting all the keys from an nested object/array.
It will recursively check for the object inside an array.
function Keys() {
let keys = [];
this.pushKey = function (key) {
keys.push(key);
};
this.getKeys = function () {
return keys;
};
}
let keys = new Keys();
let arr = [
{
a: 1,
b: {
c: [{ d: 1, e: [{ f: 1 }] }],
},
},
{
g: 1,
h: {
i: [{ j: 1, k: [{ l: 1 }] }],
},
},
];
function getObject(arr) {
for (let item of arr) {
if (Array.isArray(item)) getObject(item);
else getKeys(item);
}
}
function getKeys(obj) {
for (let key in obj) {
if (Array.isArray(obj[key])) getObject(obj[key]);
else if (typeof obj[key] === "object") getKeys(obj[key]);
keys.pushKey(key);
}
}
getObject(arr);
console.log(keys.getKeys());