How can i get key of nested object = used For....in? - javascript

Here is my code. How can i get the key of the key-value pair using for loop?
var apartment = {
bedroom: {
area: 20,
bed: {
type: 'twin-bed',
price: 100
}
}
};
The desired output is as follows:
/* desired results :
* bedroom
* area
* bed
* type
* price
*/
Please help

var getKeys = function(obj) {
var keys = [];
Object.keys(obj).forEach(function(key){
keys.push(key);
if(typeof obj[key] == 'object'){
keys = keys.concat(getKeys(obj[key]));
}
})
return keys;
}
Then
var keys = getKeys(apartment);

You can use a simple Regex as follow:
var apartment = {
bedroom: {
area: 20,
bed: {
type: 'twin-bed',
price: 100
}
}
};
let result = [];
let jsonstr = JSON.stringify(apartment);
// {"bedroom":{"area":20,"bed":{"type":"twin-bed","price":100}}}
let regex = /"(\w+)":/g;
jsonstr.replace(regex, function(match,prop){
result.push(prop);
});
console.log(result);

we can easily done by using regex, convert object string and apply regex to extract the particular word
run the snippet for required output
var apartment = {
bedroom: {
area: 20,
bed: {
type: 'twin-bed',
price: 100
}
}
};
apartment = JSON.stringify(apartment);
var re = /(")\w+(")(:)/g;
var match;
do {
match = re.exec(apartment);
if (match) {
console.log(match[0]);
}
} while (match);
regex : /(")\w+(")(:)/g
only extracts key for more click here
do while loop responsible to detect multiple match in the string

You can use a recursive function :
function getKeys(source, dest) {
for (let key in source) {
if (typeof source[key] == 'object') {
dest.push(key)
getKeys(source[key], dest)
} else {
dest.push(key)
}
}
return dest
}
result = []
const apartment = {
bedroom: {
area: 20,
bed: {
type: 'twin-bed',
price: 100
}
}
}
getKeys(apartment, result) // ["bedroom", "area", "bed", "type", "price"]

var inputs = [
{a:1,b:2,c:3}, // Simple object
{a:{b:2,c:3}}, // Simple object with nesting
{a:{a:{b:2,c:3}}}, // Repeated key hiding nesting
{a:[{b:2,c:3}]}, // keys behind array
];
inputs.push(inputs); // reference cycle and array at top
function getKeys(obj) {
var all = {};
var seen = [];
checkValue(obj);
return Object.keys(all);
function checkValue(value) {
if (Array.isArray(value)) return checkArray(value);
if (value instanceof Object) return checkObject(value);
}
function checkArray(array) {
if (seen.indexOf(array) >= 0) return;
seen.push(array);
for (var i = 0, l = array.length; i < l; i++) {
checkValue(array[i]);
}
}
function checkObject(obj) {
if (seen.indexOf(obj) >= 0) return;
seen.push(obj);
var keys = Object.keys(obj);
for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i];
all[key] = true;
checkValue(obj[key]);
}
}
}
var result = inputs.map(getKeys);
console.log(result);

Related

Javascript Parsing Key Value String to JSON

I'm currently working on trying to create a UDF to split a key value pair string based on web traffic into JSON.
I've managed to get as far as outputting a JSON object but I'd like to be able to dynamically add nested items based on the number of products purchased or viewed based on the index number of the key.
When a product is only viewed, there is always only one product in the string. Only when its a transaction is it more than one but I think it would be good to conform the structure of the json and then identify a purchase or view based on the presence of a transactionid. For example:
Item Purchased:
sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58
The output should look something like this:
[
{
"sessionid":12345,
"transactionid":555555,
"transactionamount":58
},
[
{
"productline":1,
"product":"apples",
"productprice":12,
"productqty":1
},
{
"productline":2,
"product":"pears",
"productprice":23,
"productqty":2
}
]
]
Item Viewed:
sessionid=12345&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3
[
{
"sessionid":12345,
"transactionid":0,
"transactionamount":0
},
[
{
"productline":1,
"product":"apples",
"productprice":12,
"productqty":1
}
]
]
The result I'll be able to parse from JSON into a conformed table in a SQL table.
What I've tried so far is only parsing the string, but its not ideal to create a table in SQL because the number of purchases can vary:
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
function splitstring(queryString) {
var dictionary = {};
if (queryString.indexOf('?') === 0) {
queryString = queryString.substr(1);
}
var parts = queryString.split('&');
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
// Step 2: Split Key/Value pair
var keyValuePair = p.split('=');
var key = keyValuePair[0];
var value = keyValuePair[1];
dec_val = decodeURIComponent(value);
final_value = dec_val.replace(/\+/g, ' ');
dictionary[key] = final_value;
}
return (dictionary);
}
console.log(splitstring(string));
Thanks in advance!!!
Feel like this would be less clunky with better param naming conventions, but here's my take...
function parseString(string) {
var string = string || '',
params, param, output, i, l, n, v, k, pk;
params = string.split('&');
output = [{},
[]
];
for (i = 0, l = params.length; i < l; i++) {
param = params[i].split('=');
n = param[0].match(/^product.*?([0-9]+).*/);
v = decodeURIComponent(param[1] || '');
if (n && n[1]) {
k = n[1];
output[1][k] = output[1][k] || {};
output[1][k]['productline'] = k;
pk = n[0].replace(/[0-9]+/, '');
output[1][k][pk] = v;
} else {
output[0][param[0]] = v;
}
}
output[1] = output[1].filter(Boolean);
return output;
}
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
console.log(parseString(string));
output:
[
{
"sessionid": "12345",
"transactionid": "555555",
"transactionamount": "58"
},
[{
"productline": "1",
"product": "1",
"productprice": "12"
}, {
"productline": "2",
"product": "3",
"productprice": "23"
}]
]
There's probably a far nicer way to do this, but I just wrote code as I thought about it
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
function splitstring(queryString) {
var dictionary = {};
if (queryString.indexOf('?') === 0) {
queryString = queryString.substr(1);
}
var parts = queryString.split('&');
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
// Step 2: Split Key/Value pair
var keyValuePair = p.split('=');
var key = keyValuePair[0];
var value = keyValuePair[1];
dec_val = decodeURIComponent(value);
final_value = dec_val.replace(/\+/g, ' ');
dictionary[key] = final_value;
}
return (dictionary);
}
function process(obj) {
let i = 1;
const products = [];
while(obj.hasOwnProperty(`product${i}`)) {
products.push({
[`product`]: obj[`product${i}`],
[`productprice`]: obj[`productprice${i}`],
[`productqty`]: obj[`product${i}qty`]
});
delete obj[`product${i}`];
delete obj[`productprice${i}`];
delete obj[`product${i}qty`];
++i;
}
return [obj, products];
}
console.log(process(splitstring(string)));
By the way, if this is in the browser, then splitstring can be "replaced" by
const splitstring = string => Object.fromEntries(new URLSearchParams(string).entries());
var string = "sessionid=12345&transactionid=555555&product1=apples&productprice1=12&product1qty=1&product2=pears&productprice2=23&product2qty=3&transactionamount=58";
function process(string) {
const splitstring = queryString => {
var dictionary = {};
if (queryString.indexOf('?') === 0) {
queryString = queryString.substr(1);
}
var parts = queryString.split('&');
for (var i = 0; i < parts.length; i++) {
var p = parts[i];
// Step 2: Split Key/Value pair
var keyValuePair = p.split('=');
var key = keyValuePair[0];
var value = keyValuePair[1];
dec_val = decodeURIComponent(value);
final_value = dec_val.replace(/\+/g, ' ');
dictionary[key] = final_value;
}
return (dictionary);
};
let i = 1;
const obj = splitstring(string);
const products = [];
while (obj.hasOwnProperty(`product${i}`)) {
products.push({
[`product`]: obj[`product${i}`],
[`productprice`]: obj[`productprice${i}`],
[`productqty`]: obj[`product${i}qty`]
});
delete obj[`product${i}`];
delete obj[`productprice${i}`];
delete obj[`product${i}qty`];
++i;
}
return [obj, products];
}
console.log(process(string));

Flatten a nested objects to one dimensional array javascript

I have a nested objects in this structure:
myArray = {
"D": {
"U": {
"A300": "B300",
"A326": "B326",
"A344": "B344",
"A345": "B345"
},
"P": {
"A664": "B664",
"A756": "B756"
}
},
"I": {
"U": {
"A300": "B300",
"A326": "B326"
},
"P": {
"A756": "B756"
}
}
};
I am trying to get the data out of it to be only one dimensional (Flatten). I tried the code below but it doesn't work:
var myNewArray = [].concat.apply([], myArray);
and
var myNewArray = myArray.reduce(function(prev, curr) {
return prev.concat(curr);
});
I want myNewArray to have ["B300","B326","B344","B345","B664","B756"]
You can do something like this:
var myArray = [];
myArray[0] = [];
myArray[0][0] = [];
myArray[0][0][0] = [];
myArray[0][0][1] = [];
myArray[0][1] = [];
myArray[0][1][0] = [];
myArray[0][0][0][0] = "abc1";
myArray[0][0][0][1] = "abc2";
myArray[0][0][1][0] = "abc3";
myArray[0][1][0][1] = "abc4";
myArray[0][1][0][1] = "abc5";
function flat(acc, val){
if(Array.isArray(val)){
acc = acc.concat(val.reduce(flat, []));
}else{
acc.push(val);
}
return acc;
}
var newMyArray = myArray.reduce(flat, []);
console.log(newMyArray);
What this does is to recursively reduce all the inner values that are arrays.
It seems that you're dealing with an object. The previous title of your question and the name of the variable are misleading.
In any case, flattening an object is a very similar process.
var myArray = {"D":{"U":{"A300":"B300","A326":"B326","A344":"B344","A345":"B345"},"P":{"A664":"B664","A756":"B756"}},"I":{"U":{"A300":"B300","A326":"B326"},"P":{"A756":"B756"}}};
function flatObj(obj){
return Object.keys(obj).reduce(function(acc, key){
if(typeof obj[key] === "object"){
acc = acc.concat(flatObj(obj[key]));
}else{
acc.push(obj[key]);
}
return acc;
}, []);
}
var newMyArray = flatObj(myArray);
console.log(newMyArray);
I just wanted to add my 2 cents since I was following this question and working on an answer before I left work. I'm home now so I want to post what I came up with.
const obj = {
x1: {
y1: {
z1: {
h1: 'abc',
h2: 'def'
},
z2: {
h1: 123,
h2: 456
}
}
}
}
const valAll = getPropValuesAll(obj)
console.log(valAll)
function getPropValuesAll(obj, result = []){
for(let k in obj){
if(typeof obj[k] !== 'object'){
result.push(obj[k])
continue
}
getPropValuesAll(obj[k], result)
}
return result
}
It would be easy and safe answer.
var myArray = [["abc1"],[["abc2",,"abc3"]],"abc4",{"r5": "abc5", "r6": "abc6"}];
var myNewArray = [];
function flatten(arr){
if(Array.isArray(arr)){
for(var i = 0, l = arr.length; i < l; ++i){
if(arr[i] !== undefined){
flatten(arr[i])
}
}
} else if (typeof arr === 'object') {
for(var key in arr){
if(arr.hasOwnProperty(key)){
flatten(arr[key])
}
}
} else {
myNewArray.push(arr)
}
}
flatten(myArray)
console.log(myNewArray)

How to convert square bracket object keys from URL location into nested object in Javascript?

With:
var obj = { "object[foo][bar][ya]": 100 };
How can I create:
var obj = { object: { foo: { bar: { ya: 100 }}}};
Manual approach
Split the given string with bracket, then iterate through the resultant tokens to make the nested object:
Given
var obj = { "object[foo][bar][ya]": 100 };
Split them so we get
var tokens = Object.keys(obj)[0]
.split('[')
.map(function(s){return s.replace(']','')});
// tokens = [ 'object', 'foo', 'bar', 'ya' ]
Then make the nested object, inside out
var result = {};
tokens.reverse().forEach(function(key){
if (Object.keys(result).length==0){
result[key] = obj[Object.keys(obj)[0]]; // inner-most key-value
}
else{
var temp = {};
temp[key] = result;
result = temp;
}
});
Result
{"object":{"foo":{"bar":{"ya":100}}}}
Their is no native things in javascript fr parsing nested object in querystring.
You can use http://medialize.github.io/URI.js/ which is pretty damn good at the job.
console.log(URI.parseQuery("?&foo=bar&&foo=bar&foo=baz&"));
If you don't want to import the full library, this is just the part for querystring parsing (full credit to https://github.com/medialize/URI.js):
var URI = {
decodeQuery: function(string, escapeQuerySpace) {
string += '';
try {
return decodeURIComponent(escapeQuerySpace ? string.replace(/\+/g, '%20') : string);
} catch(e) {
// we're not going to mess with weird encodings,
// give up and return the undecoded original string
// see https://github.com/medialize/URI.js/issues/87
// see https://github.com/medialize/URI.js/issues/92
return string;
}
},
parseQuery: function(string, escapeQuerySpace) {
if (!string) {
return {};
}
// throw out the funky business - "?"[name"="value"&"]+
string = string.replace(/&+/g, '&').replace(/^\?*&*|&+$/g, '');
if (!string) {
return {};
}
var items = {};
var splits = string.split('&');
var length = splits.length;
var v, name, value;
for (var i = 0; i < length; i++) {
v = splits[i].split('=');
name = URI.decodeQuery(v.shift(), escapeQuerySpace);
// no "=" is null according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#collect-url-parameters
value = v.length ? URI.decodeQuery(v.join('='), escapeQuerySpace) : null;
if (Object.prototype.hasOwnProperty.call(items, name)) {
if (typeof items[name] === 'string') {
items[name] = [items[name]];
}
items[name].push(value);
} else {
items[name] = value;
}
}
return items;
}
};
You could get the parts and build a new object.
const obj = {
"object[foo][bar][ya]": 100,
"object[foo][baz]": 200,
"object[foo][bar][bar]": 50,
"xy": 30
};
let newObj = {};
for (const i in obj) {
let a = i.match(/([^\[\]]+)(\[[^\[\]]+[^\]])*?/g),
p = obj[i];
j = a.length;
while (j--) {
q = {};
q[a[j]] = p;
p = q;
}
// merge object
let k = Object.keys(p)[0],
o = newObj;
while (k in o) {
p = p[k];
o = o[k];
k = Object.keys(p)[0];
}
o[k] = p[k];
}
console.log(newObj);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here's an es6 version. Caution: Hasn't been tested for edge cases.
const keyPattern = /^(\w+)\[(\w+)\](.*)$/;
export function decodeParams(params) {
return Object.keys(params).reduce((result, key) => {
let match = key.match(keyPattern);
if (match && match.length >= 3) {
let [key, nextKey, rest = ''] = match.slice(1);
result[key] = Object.assign(
{},
result[key],
decodeParams({ [nextKey + rest]: params[key] })
);
} else {
result[key] = params[key];
}
return result;
}, {});
}

Merge Object & Array: Javascript, JQuery

Illustrative example:
d1 = {
"ean_code": ["OA13233394CN08", "8903327046534", "8903327014779"],
"balance_qty": [5, 10, 15]
}
And
d2 = {
"ean_code": ["OA13233394CN11", "OA13233394CN08", "8903327014779", "OA13233394CN09"],
"scanned_qty": [30, 5, 20, 10, - 1],
}
Output:
d3 = {
"ean_code": ["OA13233394CN08", "8903327046534", "8903327014779", "OA13233394CN11", "OA13233394CN09"],
"scanned_qty": [5, 0, 20, 30, 10],
"balance_qty": [5, 10, 15, 0, 0]
}
Explaination. d3['scanned_qty'][1] default value is 0, because value of d3['ean_code'][1] is belongs to d1['ean_code'] array and d1 object doesn't have scanned_qty key.
Best possible way to do this operation?
You just need a custom solution for your specific case.
Merge 2 objects with no sub-objects (no recursion required)
Final object's array fields must be the same length
Final object's array fields must preserve index coherency
Final object's array fields must use '0' as a default value
http://jsfiddle.net/8X5yB/4/
function customMerge(a, b, uniqueKey) {
var result = {};
var temp = {};
var fields = {};
// object 1
for(var x=0; x<a[uniqueKey].length; x++) {
id = a[uniqueKey][x];
if(temp[id] == null) temp[id] = {};
for(k in a) {
if(k != uniqueKey) {
fields[k] = '';
temp[id][k] = (a[k].length > x ? a[k][x] : 0);
}
}
}
// object 2
for(var x=0; x<b[uniqueKey].length; x++) {
id = b[uniqueKey][x];
if(temp[id] == null) temp[id] = {};
for(k in b) {
if(k != uniqueKey) {
fields[k] = '';
temp[id][k] = (b[k].length > x ? b[k][x] : 0);
}
}
}
// create result
result[uniqueKey] = [];
for(f in fields) result[f] = [];
for(k in temp) {
result[uniqueKey].push(k);
for(f in fields) {
result[f].push(temp[k][f] != null ? temp[k][f] : 0);
}
}
return result;
}
...
var obj = customMerge(d1, d2, "ean_code");
Let's assume you have o1 and o2 as object 1 and 2, respectively.
var key,
result = {}
i,
largestLength = 0,
copyIntoResult = function (obj, key) {
for (i = 0; i < obj[key].length; i += 1) {
if (result[key].indexOf(obj[key][i]) === -1) {
result[key].push(obj[key][i]);
}
}
};
for (key in o1) {
if (o1.hasOwnProperty(key) && o2.hasOwnProperty(key)) {
result[key] = [];
copyIntoResult(o1, key);
copyIntoResult(o2, key);
if (result[key].length > largestLength) {
largestLength = result[key].length;
}
} else if (o1.hasOwnProperty(key)) {
result[key] = [].concat(o1[key]);
if (o1[key].length > largestLength) {
largestLength = o1[key].length;
}
}
}
for (key in o2) {
if (o2.hasOwnProperty(key) && !result[key]) {
result[key] = [].concat(o2[key]);
if (o2[key].length > largestLength) {
largestLength = o2[key].length;
}
}
}
// result now has the merged result
for (key in result) {
if (result[key].length < largestLength) {
for (i = 0; i < (largestLength - result[key].length); i += 1) {
result[key].push('');
}
}
}
EDIT: Upon the edit to your question, you can have all the arrays be the same length by equalizing the arrays to the maximum array length of the merged result. However, the default "blank" entry is up to you (in this case, I just used an empty string).
function merge(a,b) {
var c = {};
for(key in a.keys()) {
c[key] = a[key].slice(0);
}
for(key in b.keys()) {
if(typeof c[key] == 'undefined') {
c[key] = b[key].slice(0);
} else {
var adds = b[key].filter(function(item){
return (a[key].indexOf(item) == -1);
});
c[key].concat(adds);
}
}
return c;
}
.keys() method since v1.8.5, snippet for older browsers.
filter since v1.6, snippet for older browsers.
concat since v1.2.

Javascript Recursion for creating a JSON object

needing some advice on how to do this properly recursively.
Basically what I'm doing, is entering in a bunch of text and it returns it as JSON.
For example:
The text:
q
b
name:rawr
Returns:
[
"q",
"b",
{
"name": "rawr"
}
]
And the following input:
q
b
name:rawr:awesome
Would return (output format is not important):
[
"q",
"b",
{
"name": {
"rawr": "awesome"
}
}
]
How can I modify the following code to allow a recursive way to have objects in objects.
var jsonify = function(input){
var listItems = input, myArray = [], end = [], i, item;
var items = listItems.split('\r\n');
// Loop through all the items
for(i = 0; i < items.length; i++){
item = items[i].split(':');
// If there is a value, then split it to create an object
if(item[1] !== undefined){
var obj = {};
obj[item[0]] = item[1];
end.push(obj);
}
else{
end.push(item[0]);
}
}
// return the results
return end;
};
I don't think recursion is the right approach here, a loop could do that as well:
var itemparts = items[i].split(':');
var value = itemparts.pop();
while (itemparts.length) {
var obj = {};
obj[itemparts.pop()] = value;
value = obj;
}
end.push(value);
Of course, as recursion and loops have equivalent might, you can do the same with a recursive function:
function recurse(parts) {
if (parts.length == 1)
return parts[0];
// else
var obj = {};
obj[parts.shift()] = recurse(parts);
return obj;
}
end.push(recurse(items[i].split(':')));
Here is a solution with recursion:
var data = [];
function createJSON(input) {
var rows = input.split("\n");
for(var i = 0; i < rows.length; i++) {
data.push(createObject(rows[i].split(":")));
}
}
function createObject(array) {
if(array.length === 1) {
return array[0];
} else {
var obj = {};
obj[array[0]] = createObject(array.splice(1));
return obj;
}
}
createJSON("p\nq\nname:rawr:awesome");
console.log(data);

Categories

Resources