How do you convert an object with duplicate keys to JSON/String? - javascript

Imagine you have an object like this:
var obj = {
name: "Mike",
name: "George",
age: 24,
}
Converting this to JSON with JSON.stringify(obj) yields:
{"name":"George","age":24}
This causes loss of data and isn't something we want.
Converting this to a string with toString() yields
[object Object]
, which isn't what we want either.
How does one go about this?
PS: I am aware that objects can't have two identical keys.
So after some brainstorming with the nice users that have commented here, a simple way to deal with this is to just turn it into a string manually. Like this:
var obj = `
name: "Mike",
name: "George",
age: 24,
`;
Then just parse it to your heart's content. For me personally, this could be a way to do it. However, this will obviously depend on the user-case.
var obj2 = {};
str = str.split(",").map(e => e.replace(/(\")/gi, "").trim());
str.forEach((e, i) => {
var temp = e.slice(0, e.indexOf(":"));
if(obj2[temp]) obj2[temp].push(e.slice(e.indexOf(":") + 1).trim());
else obj2[e.slice(0, e.indexOf(":"))] = [e.slice(e.indexOf(":") + 1).trim()];
})
The code above just splits the string based on some desired separator and processes the given array further. This might be a indelicate way to solve the question, but it works for my scenario :/. It yields the following JSON-object:
{"name":["Mike","George"],"age":["24"]}

Right after your object is defined, the second "name" key will override the first "name" key.
You can re-structure your object like this:
var obj = {
name: ["Mike","George"],
age: 24,
}
or
var arrayObj = [{
name: "Mike",
age: 24,
},{
name: "George",
age: 24,
}]
and use the built-in function for string in js to get your expected result.
Hope this helps!

You can't do it. the "name" value is the second value assigned to "name" key in javascript object or JSON. try to use obj.name it will be "George"
This is workaround to do what are you need.you can use "_" or any unused symbol.
const obj = {
name: 'ahmed',
_name: 'elmetwally',
title: 'js dev',
};
console.log(JSON.stringify(obj).replace(/\_/g, ''));

Here's a simple method to convert a string representation of the object into an array of key-value pairs.
It's not a general method, but it should work fine for an object with no nesting.
let result = document.getElementById('result');
let jsonStr = `{ name: "Mike", name: "George", age: 24 }`;
result.innerHTML = `jsonStr: "${jsonStr}"\n`;
// strip out '{}'
let jsonClean = jsonStr.replace(/{/g, '').replace(/}/g, '');
result.innerHTML += `jsonClean: "${jsonClean}"\n`;
// split jsonClean into array of key-value strings
let kvStrings = jsonClean.split(',');
result.innerHTML +=
`kvStrings: ${JSON.stringify(kvStrings)}\n`;
// form array of key-value pairs
let kvPairs = kvStrings.map(kvstr => {
let [key, value] = kvstr.split(':').map(el => el.trim());
// strip double quotes or convert to number
if (value.includes('"')) {
value = value.replace(/"/g, '');
} else {
value = Number.parseFloat(value);
}
return [key, value];
});
result.innerHTML += `kvPairs: ${JSON.stringify(kvPairs)}`;
<pre id="result"></pre>

So after some brainstorming with the nice users that have commented here, a simple way to deal with this is to just turn it into a string manually. Like this:
var obj = `
name: "Mike",
name: "George",
age: 24,
`;
Then just parse it to your heart's content. For me personally, this could be a way to do it. However, this will obviously depend on the user-case.
var obj2 = {};
str = str.split(",").map(e => e.replace(/(\")/gi, "").trim());
str.forEach((e, i) => {
var temp = e.slice(0, e.indexOf(":"));
if(obj2[temp]) obj2[temp].push(e.slice(e.indexOf(":") + 1).trim());
else obj2[e.slice(0, e.indexOf(":"))] = [e.slice(e.indexOf(":") + 1).trim()];
})
The code above just splits the string based on some desired separator and processes the given array further. This might be a indelicate way to solve the question, but it works for my scenario :/. It yields the following JSON-object:
{"name":["Mike","George"],"age":["24"]}

Related

Best way to alter array of objects inside an object (using a string path)

This may be simpler than I think but is there an easy way to alter the array inside this object using a string:
var temp = {
members: [
{file_name: 'abc', file_link: 'www'}
]
}
This is what I am trying to achieve:
const name = "members[0].file_name" // STRING
temp = {...temp, [name]: 'changed'}
Output it's giving me:
Yes I can split that string to give me the keys and index then change the object the normal way but I was just wondering if there is an easier way about it.
You can take a look at lodash's set function that takes in a string path, and returns the nested object.
lodash does the parsing for you, so you don't have to
https://dustinpfister.github.io/2018/12/04/lodash_set/
You can use the eval() function which will return the object you want in accordance with a path
const temp = {
members: [{
file_name: 'abc',
file_link: 'www'
}]
}
const path = "members[0].file_name";
// Obtain last key (file_name)
const lastKey = path.split(".").at(-1);
// Obtain the path to the last key (members[0])
const previousPath = path.substr(0, path.length - (lastKey.length + 1));
// Get the object with the path (temp.members[0])
const e = eval(`temp.${previousPath}`)
// Modify object
e[lastKey] = "xyz";
console.log(temp)
You can achieve this the following way
var temp = {
members: [
{file_name: 'abc', file_link: 'www'}
]
}
const name = "file_name" // STRING
temp.members[0][name] = "changed";
console.log(temp);
Or like this:
var temp = {
members: [
{file_name: 'abc', file_link: 'www'}
]
}
const name = "file_name";
const arr = "members";
temp[arr][0][name] = "changed";
console.log(temp);

how to concatenate two object and replace the values?

I'm trying to concatenate two objects. I need to merge the two object and based on the "beforeVist" object value within the arrow.
My two objects down below:
const beforeVist = {
name : '<<name>>',
age : '<<age>>',
place : '<<place>>'
};
const afterVist = {
name : 'Robin',
age : 22,
place : 'Mars'
}
var Updated = {...afterVist, ...beforeVist};
console.log(Updated)
when I'm trying do console.log() function output below,
{
name : 'Robin',
age : 22,
place : 'Mars'
}
this is what my expected output is. I'm not sure that it is the right way.
Thanks advance!!!
You could also use Object.assign
const a = {p1: 12, p2: 23}
const b = {p2: 34, p3: 'adfa'}
let c = Object.assign(b, a)
// c contains:
{p2: 23, p3: "adfa", p1: 12}
If you care about immutability, you can provide separate "result" object:
const res = Object.assign({}, b, a)
// a and b still hold the original values
NOTE: properties ORDER will be driven from left-to-right ("p2" is the first prop in B, but second in A), but the VALUES from right-to-left(result.p2 contains value from the rightMost object with such property - ie A.p2 overrides B.p2
It is the right way. You should use object sprad
let merged = {...obj1, ...obj2};
Method for ES5 and Earlier
for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }
Because << >> are always at the first two places and the last two places we can simply slice and then reassign the value.
const beforeVist = {
name: '<<name>>',
age: '<<age>>',
place: '<<place>>'
};
const afterVist = {
name: '<<Robin>>',
age: '<<22>>',
place: '<<Mars>>'
}
var Updated = {...beforeVist, ...afterVist };
Object.entries(Updated).forEach(([key, value]) => {
let val = value.slice(2, value.length - 2);
Updated[key] = val;
})
console.log(Updated)
At the moment you are just overwriting the properties from afterVist with the properties in beforeVist, and since the property names are the same, you're essentially just making a shallow copy. This is more evident if your afterVist has different property names to beforeVist (and why I've provided different property names in beforeVist below - to show that they don't have to be the same and that the value is grabbed based on the key specified in <<key>>)
Instead, you can use Object.fromEntries() by mapping the Object.entries() of your original object, and using replace on the keys to extract the key name like so:
const beforeVist = { myName: '<<name>>', myAge: '<<age>>', myPlace: '<<place>>' };
const afterVist = { name: 'Robin', age: 22, place: 'Mars' };
const result = Object.fromEntries(Object.entries(beforeVist).map(([key, value]) => [
key,
value.replace(/<<([^>>]*)>>/, (_, g) => afterVist[g])
]));
console.log(result);

Updating javascript string to an array

I got an URL containing a bunch of parameters, hereunder the following as well;
conditions=[{"name”:”foo”,”operator”:”bar”,”value":350000}]
This can also be the folowing
conditions=[]
and
conditions=[{"name”:”one”,”operator”:”two”,”value":350000}, {"name”:”three”,”operator”:”one”,”value”:22}]
It could theoretically also be
conditions=[{"name”:”one”,”operator”:”two”,”value":350000}, {"name”:”three”,”operator”:”one”,”value”:22}, {"name”:”four”,”operator”:”two”,”value”:22}, {"name”:”sixty”,”operator”:”three”,”value”:22}, ..]
Based on an input I want to change the conditions=[]. I got the following variables in my code
inputName, obj, valueOperator
These could contain the following values:
inputName = “three”
valueOperator = “two”
obj.value = 22
So from this i can construct the conditions as describer earlier. Now to my issue;
I want to break up the conditions=[] and check if there is anything in the brackets, if not, I’ll just add my new condition. If there is something, I want to check if the inputName matches any “name” in bracket. If not, I’ll just add my new condition. If it matches I want to update the value and operator with my new variables. When I’m done I want to put back together the conditions=[]. With the updated conditions. It will always only update one condition at a time.
I'm pretty much lost. Does anybody have a great idea?
From the explanation you have provided, i tried to replicate it. Hope this works.
const inputName = 'three';
const valueOperator = 'two';
const obj = 22;
let conditions = [
{ name: 'one', operator: 'two', value: 350000 },
{ name: 'two', operator: 'one', value: 22 }
];
if (conditions.length == 0) {
conditions.push({ name: inputName, operator: valueOperator, value: obj });
} else {
let found = false;
for (const condition of conditions) {
if (condition.name == inputName) {
condition.operator = valueOperator;
condition.value = obj;
found = true; // mark found as true when name found
}
}
// Insert values if not found in conditions
if (!found) {
conditions.push({ name: inputName, operator: valueOperator, value: obj });
}
}
console.log(conditions);
If you have the following url:
https://example.com/myfolder/?conditions=[{"name”:”foo”,”operator”:”bar”,”value":350000}]
then the value of the queryString parameter conditions is a JSON string.
To turn that value into a javascript object, you need the following:
// CAPTURE THE QUERY STRING IN A URLSearchParams OBJECT INSTANCE
let urlParams = new URLSearchParams(window.location.search);
// GET THE RELEVANT JSON STRING FROM urlParams
let conditionsJSON = urlParams.get('conditions');
// CONVERT THE JSON STRING INTO A JAVASCRIPT OBJECT
let conditionsObject = JSON.parse(conditionsJSON);
You will now have an array (conditionsObject) which looks like this:
[
{
name : "foo",
operator : "bar",
value : 350000
}
]
N.B. To avoid confusion, in javascript, an array is a specific kind of object - so the code above represents both an array and an object (because the former represents a subset of the latter).
This code should work
const inputName = 'foo'
const valueOperator = 'two'
const value = 22
const conditionString = 'condition=[{"name”:”foo”,”operator”:”bar”,”value":350000}]'
const data = JSON.parse(conditionString.substr(10).replace(/”/g, '"'))
const newData = { name: inputName, operator: valueOperator, value: value }
let ind = data.findIndex(v => v.name === inputName)
if (ind < 0) ind = data.length
data[ind] = newData
const newConditionsString = `conditions=${JSON.stringify(data)}`
console.log(newConditionsString)
First part of your problem can be taken care by the solution provided by Rounin. For the second part where you want to work on condition matching based on name, below code should be able to help you.
inputName="Three"
valueOperator = "two"
value = 22
if(conditionsObject.length!=0){
let index = conditionsObject.findIndex((item)=>item.name==inputName)
if(index!=-1){
conditionsObject[index].value = value
conditionsObject[index].operator = valueOperator
}
else{
conditionsObject.push({ name: inputName, operator: valueOperator, value: value })
}
else{
conditionsObject.push({ name: inputName, operator: valueOperator, value: value })
}
}

How to create an array of objects with key/value pairs from selector variables in $each function?

I am trying to create a new object in jquery with the values of multiple selectors. For example:
loopSelector = $('.myClass');
loopSelector.each(function(i, elem) {
var1 = $(elem).parents('li').text();
var2 = $(elem).parents('p').text();
var newArray = [{
animal: var1
age: var2
}];
console.log(newArray);
}
In the console I get:
Array(1)
0: {animal: 'cat', age: 12}
Array(1)
0: {animal: 'dog', age: 5}
Array(1)
0: {animal: 'goat', age: 7}
But when I try to console.log(newArray.age); I get undefined 3 times. My goal is to compare all of the objects by the value of age.
Is there a better way of doing this?
Since you want to create an array of the same elements selected, just with a different data representation for each, consider using .map() instead of .each():
loopSelector = $('.myClass');
var array = loopSelector.map(function (i, elem) {
var animal = $(elem).parents('li').text();
var age = $(elem).parents('p').text();
return {
animal: animal,
age: age
};
}).get();
console.log(array);
Note the use of .get() at the end (as pointed out by Taplar in the comments), which converts the jQuery object into a regular Javascript array.
Or with some fancy ES6 features thrown in to tidy things up a little:
const array = $('.myClass').map((i, elem) => {
const animal = $(elem).parents('li').text();
const age = $(elem).parents('p').text();
return { animal, age };
}).get();
console.log(array);
You can try the below code snippet to access object directly:
loopSelector = $('.myClass');
var newArray = [];
loopSelector.each(function(i, elem) {
var obj = {};
var1 = $(elem).parents('li').text();
var2 = $(elem).parents('p').text();
obj.animal = var1;
obj.age = var2;
newArray.push(obj);
}
newArray.map(val => {
//Here your will be able to access directly to objects with key name.
console.log(val)
});

storing key value pairs in an array in javascript

I have 2 arrays namely,
configdata = ["assignee", "shortDesc"];
ticketarray = ["Tom","testDesc"];
I want to store the values as a key value pair in another array, something like this:
ticketData = ["assignee":"Tom","shortDesc":"testDesc"];
Kindly note that the array values are dynamic, so I cannot hardcode them.
Is there a way to do so? I am able to achieve the above said requirement but the length always shows 0. This is the code that I am using:
configdata.Incident_Field.forEach(function (k, i) {
this[k] = ticketarray[i];
}, ticketData);
Other people have explained why your code did not work. I am providing another solution using reduce.
const configdata = ["assignee", "shortDesc"];
const ticketarray = ["Tom", "testDesc"];
let ticketData = configdata.reduce((result, value, index) => {
result[value] = ticketarray[index];
return result;
}, {});
console.log(ticketData);
Output:
{
assignee: "Tom",
shortDesc: "testDesc"
}
The below is not a valid structure in JavaScript:
ticketData = ["assignee":"Tom","shortDesc":"testDesc"];
What you need is a JavaScript object. The best you can do is:
Make sure both the array lengths are same.
Associate the key and value by creating a new object.
Use Object.keys(obj).length to determine the length.
Start with the following code:
configdata = ["assignee", "shortDesc"];
ticketarray = ["Tom", "testDesc"];
if (configdata.length == ticketarray.length) {
var obj = {};
for (var i = 0; i < configdata.length; i++)
obj[configdata[i]] = ticketarray[i];
}
console.log("Final Object");
console.log(obj);
console.log("Object's Length: " + Object.keys(obj).length);
The above will give you an object of what you liked, a single variable with all the values:
{
"assignee": "Tom",
"shortDesc": "testDesc"
}

Categories

Resources