Iterate over a Javascript Object and perfom conditional on values - javascript

So i have a JS Object like that :
let object =
{
"key1":"value1",
"key2":"value2",
"key3":"value3"
}
For iterating, i use this : for (let i = 0; i < Object.keys(object).length; i++)
Now, what i want to do is basically this :
let value;
if (data === undefined || data === "") {
value = []
} else if (data.includes(",")) {
value = data.split(",")
} else if (data.includes(".")) {
value = data.split(".")
} else {
value = data.split(" ");
}
So, i tried Object.values(entries_array).split(",") but split is not an Object method. So if you can help me to find a solution.
Thanks in advance.
Edit: Sorry, i'll try to describe more what i want to achieve. I want with the code, to obtain my object variable changed with the same keys but with the values splitted.
For example if the value has a comma, i want to split the value. If not, do nothing.
For now, i have this :
let object =
{
"key1":"value1",
"key2":"value2",
"key3":"value3"
}
const entries = Object.entries(object);
const entries_array = Object.fromEntries(entries)
let data_val;
for (let i = 0; i < Object.keys(entries_array).length; i++) {
Object.values(entries_array).forEach(val => {
if (val === undefined || val === "") {
data_val = []
} else if (val.includes(",")) {
data_val = val.split(",")
} else if (val.includes(".")) {
data_val = val.split(".")
} else {
data_val = val.split(" ");
}
});
}
return entries_array;

function reassignValueAsArray(obj, [key, value]) {
obj[key] = value.split(/\s*[., ]\s*/);
return obj;
}
function reassignKeyValuesAsArray(obj) {
return Object
.entries(obj)
.reduce(reassignValueAsArray, obj);
}
const sampleObject = {
"key1": "value1,value1b",
"key2": "value2.value2b",
"key3": "value3 value3b",
"key4": "value4.value4b,value4c value4d",
"key5": "value5-value5b-value5c-value5d",
};
reassignKeyValuesAsArray(sampleObject);
console.log(sampleObject);
.as-console-wrapper { min-height: 100%!important; top: 0; }

Related

A way to convert an object with keys of . seperated strings into a JSON object

I'm trying to figure out a way to turn and object like this :
{ "test.subtest.pass" : "test passed", "test.subtest.fail" : "test failed" }
into JSON like this:
{ "test": { "subtest": { "pass": "test passed", "fail": "test failed" }}}
sometimes there may be duplicate keys, as above perhaps there would be another entry like "test.subtest.pass.mark"
I have tried using the following method and it works but it's incredibly ugly:
convertToJSONFormat() {
const objectToTranslate = require('<linkToFile>');
const resultMap = this.objectMap(objectToTranslate, (item: string) => item.split('.'));
let newMap:any = {};
for (const [key,value] of Object.entries(resultMap)) {
let previousValue = null;
// #ts-ignore
for (const item of value) {
// #ts-ignore
if (value.length === 1) {
if(!newMap.hasOwnProperty(item)) {
newMap[item] = key
} // #ts-ignore
} else if (item === value[value.length - 1]) {
if(typeof previousValue[item] === 'string' ) {
const newKey = previousValue[item].toLowerCase().replace(/\s/g, '');;
const newValue = previousValue[item];
previousValue[item] = {};
previousValue[item][newKey] = newValue;
previousValue[item][item] = key;
} else {
previousValue[item] = key;
}
} else if (previousValue === null) {
if (!newMap.hasOwnProperty(item)) {
newMap[item] = {};
}
previousValue = newMap[item];
} else {
if (!previousValue.hasOwnProperty(item)) {
previousValue[item] = {}
previousValue = previousValue[item];
} else if (typeof previousValue[item] === 'string') {
const newValue = previousValue[item];
previousValue[item] = {};
previousValue[item][item] = newValue;
} else {
previousValue = previousValue[item];
}
}
}
}
return newMap;
}
We can utilize recursion to make the code a little less verbose:
function convertToJSONFormat(objectToTranslate) {
// create root object for the conversion result
const result = {};
// iterate each key-value pair on the object to be converted
Object
.entries(objectToTranslate)
.forEach(([path, value]) => {
// utilize a recursive function to write the value into the result object
addArrayPathToObject(result, path.split("."), value);
});
return result;
}
function addArrayPathToObject(root, parts, value) {
const p = parts.shift();
// base-case: We attach the value if we reach the last path fragment
if (parts.length == 0) {
root[p] = value
return;
}
// general case: check if root[p] exists, otherwise create it and set as new root.
if(!root[p]) root[p] = {};
addArrayPathToObject(root[p], parts, value)
}
This function utilizes the fact that objects are pass-by-reference to recursively traverse through the object starting at its root until setting the desired value.
You can add error-handling and other such concerns as necessary for your use.
#Meggan Naude, toJson function copies json object to reference obj for provided keys and value.
const p = { "test.subtest.pass" : "test passed", "test.subtest.fail" : "test failed" };
const result = {} ;
const toJson = (obj, keys, value) => {
if (keys?.length === 1) {
obj[keys[0]] = value;
return obj
} else {
const k = keys.splice(0, 1)
if (k in obj) {
toJson(obj[k], keys, value)
} else {
obj[k] = {};
toJson(obj[k], keys, value)
}
return obj
}
}
Object.keys(p).forEach(key => toJson(result, key.split('.'), p[key]))
console.log(result);

Clear a variable counter inside forEach loop?

I'm trying to reset a (file public) counter that is used inside a recursive forEach loop.
Basically the code below checks the length of the innermost key-value pair where:
length = (key length) + (some strings inserted) + (key value)
var container = ''
var length = 0
function getUpdatedLengthOfInnerMostObjects (obj) {
Object.keys(obj).forEach(k => {
if (typeof obj[k] === 'object') {
getUpdatedLengthOfInnerMostObjects(obj[k])
} else {
container = k + someFunc(obj[k]) + obj[k]
length += container.length
}
})
return length
}
const sampleObj = {
"key1": {
"key2": {
"key3": {
"key4a": {
"key5a": "value5a"
},
"key4b": {
"key5b": "value5b"
},
"key4c": {
"key5c": "value5c"
},
"key4d": {
"key5d": "value5d"
}
}
}
}
}
function someFunc (obj) {
// Some string manipulation here to return variable length, just returning static for simplicity of this example
return 'xxx'
}
console.log('length 1st try = ' + getUpdatedLengthOfInnerMostObjects(sampleObj))
console.log('length 2nd try = ' + getUpdatedLengthOfInnerMostObjects(sampleObj))
So the string to get the length of is:
key5axxxvalue5akey5bxxxvalue5bkey5cxxxvalue5ckey5dxxxvalue5d
It results to lengths of 60 and 120. I need it to output 60 and 60.
"length 1st try = 60"
"length 2nd try = 120"
But not sure how to. When I add this before the return statement in the getUpdatedLengthOfInnerMostObjects(), then it always just returns 0.
const tempLength = length
length = 0
return tempLength
What am I missing here??
Fiddle here:
https://jsfiddle.net/keechan/cs3prmLx/
Help!
You must move length variable into function scope.
try it :
var container = ''
function getUpdatedLengthOfInnerMostObjects (obj) {
let length = 0
let getResult = (obj) => {
Object.keys(obj).forEach(k => {
if (typeof obj[k] === 'object') {
getResult(obj[k])
} else {
container = k + someFunc(obj[k]) + obj[k]
length += container.length
}
})
}
getResult(obj);
return length
}
const sampleObj = {
"key1": {
"key2": {
"key3": {
"key4a": {
"key5a": "value5a"
},
"key4b": {
"key5b": "value5b"
},
"key4c": {
"key5c": "value5c"
},
"key4d": {
"key5d": "value5d"
}
}
}
}
}
function someFunc (obj) {
// Some string manipulation here to return variable length, just returning static for simplicity of this example
return 'xxx'
}
console.log('length 1st try = ' + getUpdatedLengthOfInnerMostObjects(sampleObj))
console.log('length 2nd try = ' + getUpdatedLengthOfInnerMostObjects(sampleObj))
I think you really want a dig function:
function dig(obj, func){
let v;
if(obj instanceof Array){
for(let i=0,l=obj.length; i<l; i++){
v = obj[i]; func(v, i, obj);
if(typeof v === 'object' && v !== null)dig(v, func);
}
}
else{
for(let i in obj){
v = obj[i]; func(v, i, obj);
if(typeof v === 'object' && v !== null)dig(v, func);
}
}
}
const sampleObj = {
"key1": {
"key2": {
"key3": {
"key4a": {
"key5a": "value5a"
},
"key4b": {
"key5b": "value5b"
},
"key4c": {
"key5c": "value5c"
},
"key4d": {
"key5d": "value5d"
}
}
}
}
}
let results = '';
dig(sampleObj, (v,k)=>{
if(typeof v === 'string'){
results += k+'xxx'+v;
}
});
console.log(results); console.log(results.length);
Note that you may have to add more conditions if other steps give you String results in your actual Object.

Serialization of JS object with different logic for object's properties

Hi I need to convert the the numeric values of my object to string. But different properties has different transformation rules.
My sample object:
{
name: "Name"
sRatio: 1.45040404
otherMetric: 0.009993
}
I use JSON.stringify to convert my initial object.
let replacemet = {}
JSON.stringify(metrics[0], function (key, value) {
//Iterate over keys
for (let k in value) {
if ((k !== "sRatio") || (k !== "name")) {
replacemet[k] = (100*value[k]).toFixed(2) + "%"
} else {
if( k === "name") {
replacemet[k] = "yo!"+value[k]
} else{
replacemet[k] = value[k].toFixed(2)
}
}
}
})
But my conditions are not triggered and all properties are converting on the same manner.
The job of the replacer callback is not to fill in some global replacemet object but rather to return a new value.
I think you are looking for something along the lines of
JSON.stringify(sample, function (key, value) {
if (key == "sRatio") {
return value.toFixed(2);
} else if (key == "name") {
return "yo!"+value;
} else if (typeof value == "number") {
return (100*value).toFixed(2) + "%"
} else {
return value;
}
})
Try using switch block that will be really good for this. Detailed description on switch.
let replacemet = {}
JSON.stringify(metrics[0], function (key, value) {
//Iterate over keys
for (let k in value) {
switch(k) {
case "name":
replacemet[k] = "yo!"+value[k];
break;
case "sRatio":
replacemet[k] = value[k].toFixed(2);
break;
default:
replacemet[k] = value[k].toFixed(2);
}
}
})
Hope to help you . I add when dynamic property
metrics =
[
{
name: "Name",
sRatio: 1.45040404,
otherMetric:0.009993
},
{
name: "Name1",
sRatio: 2.45040404,
otherMetric: 1.009993
}
]
;
let source = JSON.stringify(metrics);
let arrJson = new Array();
//arrJson = {};
metrics.forEach(function(value){
let replacemet = {};
for(var k in value) {
if( k.toString().trim() == "name") {
replacemet[k] = "yo!"+value[k] ;
}
else
if ( ( k.toString().trim() !== "sRatio") && ( k.toString().trim() !== "name")) {
replacemet[k] = (100* value[k] ).toFixed(2).toString() + "%" ;
} else {
replacemet[k] = value[k].toFixed(2) ;
}
}
arrJson.push(JSON.stringify(replacemet)) ;
});
console.log(arrJson);

Traversing an object and picking out key/value

Im trying to create arrays from an keys in an object. I might have an object in this structure:
$scope.myobj = {
'level1': {
'level1Sub1': {
'result': 'level1-level1Sub1-result'
},
'level1Sub2': {
'result': 'level1-level1Sub2-result'
}
},
'level2': {
'level2Sub1': {
'result': 'level2-level2Sub1-result'
},
'level2Sub2': {
'result': 'level2-level2Sub2-result'
}
}
}
Elements on the same level goes in the same array.
So in this case the result should be:
TopLevelArr = [level1, level2]
SecondLevelArr = [level1Sub1, level1Sub2,level2Sub1,level2Sub2]
Im using jquery to traverse the whole object:
var path = "";
$.each($scope.myobj, walker);
function walker(key, value) {
var savepath = path;
path = path ? (path + "." + key) : key;
console.log(path)
if (value !== null && typeof value === "object") {
// Recurse into children
$.each(value, walker);
}
path = savepath;
}
This should be pretty close if I could find a way to pass the key into the proper array based on its level.
http://jsfiddle.net/bald1/ys05m1s8/2/
Help appreciated. Thank you.
You could use a iterative and recursive approach for getting all keys.
function getKeys(o) {
function iter(o, i) {
var k = Object.keys(o);
keys[i] = keys[i] || [];
k.forEach(function (kk) {
if (keys[i].indexOf(kk) < 0) {
keys[i].push(kk);
}
if (o[kk] !== null && typeof o[kk] === 'object') {
iter(o[kk], i + 1);
}
});
}
var keys = [];
iter(o, 0);
return keys;
}
var $scope = {};
$scope.myobj = { 'level1': { 'level1Sub1': { 'result': 'level1-level1Sub1-result' }, 'level1Sub2': { 'result': 'level1-level1Sub2-result' } }, 'level2': { 'level2Sub1': { 'result': 'level2-level2Sub1-result' }, 'level2Sub2': { 'result': 'level2-level2Sub2-result' } } };
console.log(getKeys($scope.myobj));
.as-console-wrapper { max-height: 100% !important; top: 0; }
var level=0;
var levelarray=[];
function looptrough(obj){
for(key in obj){
if(typeof obj[key]=="object"){
level++;
looptrough(obj[key]);
level--;
}
levelarray[level]=levelarray[level] || {};
levelarray[level][key]=obj[key];
}
}
looptrough({a:true;b:{c:true}});
Levelarray should now contain:
0:{a:true;b:{c:true}}
1:{c:true}
I thought using jquery is quite unecessary in that case, thats why i used for in...

traversing a json for empty array value

i have a below json
{
"loanDetails": [
{
"vehicleDetail": {
"RCBookImageReferences": {
"imagePathReferences": [
{
}
]
}
},
"chargeDetails": [
{
}
],
"commissionDetails": [
{
}
],
"disbursementDetails": [
{
}
]
}
]
}
in the above json i need to traverse every key and if i find it emty then set the parent as empty array ie the output should be as below
{"loanDetails":[]}
i used the code below
function isEmpty(obj) {
for(var prop in obj) {
if(obj.hasOwnProperty(prop))
return false;
}
return true;
}
But it did not give me the expected result.I'm stuck here any help will be much helpful.
The function clean takes an object and loops over its keys, calling clean recursively
on each object-valued property.
If the result of cleaning is an empty object, delete the key in question.
If the object itself turns out to be empty, return undefined, triggering deletion of the property holding that object at the higher level.
function clean(obj) {
var isEmpty = true;
for (var key in obj) {
var val = obj[key];
if (val === null || typeof val !== 'object' || (obj[key] = clean(val))) {
isEmpty = false;
} else {
delete obj[key];
}
}
return isEmpty ? undefined : obj;
}
>> a = { x: 1, b: { y: [] }, c: { d: { } } }
>> clean(a)
<< Object {x: 1}
This should make it recursive. With two solutions.
Solution 1: empty test function
var boolValue = true;
for(var prop in obj) {
if(obj.hasOwnProperty(prop) && typeof obj[prop] === 'object')
{
boolValue = recursiveIsEmpty(obj[prop]);
}
else
{
return false;
}
}
return boolValue ;
//test and set empty string
recursiveIsEmpty(jsonDataObj['loanDetails']) ? jsonDataObj['loanDetails'] = [] : null;
Solution 2 recursive empty function that empties parent obj
function recursiveIsEmpty(obj) {
var boolValue = true;
for(var prop in obj) {
if(obj.hasOwnProperty(prop) && typeof obj[prop] === 'object')
{
boolValue = recursiveIsEmpty(obj[prop]);
if (boolValue)
{
delete obj[prop]; //an object is empty. Delete from parent;
}
}
else
{
return false;
}
}
return boolValue; //returns an empty object
}
recursiveIsEmpty(jsonDataObj['loanDetails']) //returns jsonDataObj['loanDetails'] = [];
This checks if obj has a property that is an object. If so load that object and check it's properties. If not return false, because that will be string or number and that confirms the object is not empty.
Your JSON-string is not valid. When corrected, you can use a reviver function parameter (see MDN) to remove 'empty' arrays (aka properties with criteria you specify).
To be clear, the reviver function takes care of the traversing on all levels of the parsed object. If it returns undefined the property is removed from the object. The reviver used in the snippet thus removes all properties containing arrays with empty objects, or empty arrays.
The snippet demonstrates this.
// json string corrected
var foo = '{"loanDetails": [{"vehicleDetail": {"RCBookImageReferences": '+
'{"imagePathReferences": [{}]}}, "chargeDetails": [{}],'+
'"commissionDetails": [{}],"disbursementDetails": [{}]}]}';
// parse it, using reviver parameter
var fooparsed = JSON.parse( foo,
function (key, value) { //<= reviver here
return (value.length && value.length == 1 &&
value[0] instanceof Object &&
Object.keys(value[0]).length == 0) ||
value instanceof Array && !value.length
? undefined : value;
}
);
// print
Helpers.log2Screen( Object.print(fooparsed) );
<script src="http://kooiinc.github.io/JSHelpers/Helpers-min.js"></script>
if you are doing this using ajax then you should go with seriallizing the jason array using javascript.
at the time of passing data through json
data: "your data",
use this
data:$(form).serialize(),
it will pass all the key of that form which you are passing ,
if you want to see its result the try to print it on console
var inputObj = {
"loanDetails": [{
"vehicleDetail": {
"RCBookImageReferences": {
"imagePathReferences": [{}]
}
},
"chargeDetails": [{}],
"commissionDetails": [{}],
"disbursementDetails": [{}]
}, {
"vehicleDetail": {
"RCBookImageReferences": {
"imagePathReferences": [{
"Valid": "Working"
}]
}
},
"chargeDetails": [{}],
"commissionDetails": [{}],
"disbursementDetails": [{}]
}],
"Superman": {
"Name": ""
},
"SpiderMan": {
"Name": "Senthil"
}
}
function flatten(target, opts) {
var output = {},
opts = opts || {},
delimiter = opts.delimiter || '.'
function getkey(key, prev) {
return prev ? prev + delimiter + key : key
};
function step(object, prev) {
Object.keys(object).forEach(function(key) {
var isarray = opts.safe && Array.isArray(object[key]),
type = Object.prototype.toString.call(object[key]),
isobject = (type === "[object Object]" || type === "[object Array]")
if (!isarray && isobject) {
return step(object[key], getkey(key, prev))
}
output[getkey(key, prev)] = object[key]
});
if (Object.keys(object) == "") {
if (object instanceof Array) {
output[prev] = [];
} else {
output[prev] = {};
}
}
};
step(target)
return output
};
function unflatten(target, opts) {
var opts = opts || {},
delimiter = opts.delimiter || '.',
result = {}
if (Object.prototype.toString.call(target) !== '[object Object]') {
return target
}
function getkey(key) {
var parsedKey = parseInt(key)
return (isNaN(parsedKey) ? key : parsedKey)
};
Object.keys(target).forEach(function(key) {
var split = key.split(delimiter),
firstNibble, secondNibble, recipient = result
firstNibble = getkey(split.shift())
secondNibble = getkey(split[0])
while (secondNibble !== undefined) {
if (recipient[firstNibble] === undefined) {
recipient[firstNibble] = ((typeof secondNibble === 'number') ? [] : {})
}
recipient = recipient[firstNibble]
if (split.length > 0) {
firstNibble = getkey(split.shift())
secondNibble = getkey(split[0])
}
}
// unflatten again for 'messy objects'
recipient[firstNibble] = unflatten(target[key])
});
//Array Check
var keys = Object.keys(result);
if (keys.length > 0 && keys[0] === "0") {
var output = [];
keys.forEach(function(key) {
output.push(result[key])
});
return output;
}
return result
};
var flatted = flatten(inputObj);
var keys = Object.keys(flatted);
keys.forEach(function(key) {
if (JSON.stringify(flatted[key]) === "{}" || JSON.stringify(flatted[key]) == "") {
// console.log(key)
delete flatted[key];
var paths = key.split(".");
if (paths.length >= 2) {
var int = parseInt(paths[1])
if (isNaN(int)) {
key = paths[0];
flatted[key] = {};
} else {
key = paths[0] + "." + int;
flatted[key] = {};
}
var newKeys = Object.keys(flatted);
for (var j = 0; j < newKeys.length; j++) {
var omg = newKeys[j];
if (omg.indexOf(key) != -1 && omg.length > key.length) {
delete flatted[key];
}
}
}
}
})
console.log(flatted)
var output = unflatten(flatted);
alert(JSON.stringify(output))

Categories