Converting a String to Multiple objects (javascript) - javascript

I have the following string: Jack:13,Phil:15,Lucy:12I'm trying to fetch objects from this string.
This string would have 3 people objects with their ages. How can this be achieved?
I've tried the following:
var s = 'Jack:13,Phil:15,Lucy:12'
var obj1 = eval("("+s+")");
var obj2 = JSON.parse(s);
Logging any of the obj variables returns errors. Am I missing a simple trick here? Any explanation would be appreciated, thanks.

In general, if you're doing replaces on a string to turn it into something you can pass eval or JSON.parse, that's probably not your best approach. An in particular, avoid using eval (or its cousin new Function) when you can (you certainly can here), and always avoid eval (or its cousin new Function) with untrusted input.
A pair of splits with map does it:
const s = 'Jack:13,Phil:15,Lucy:12'
const people = s.split(",")
.map(e => e.split(":"))
.map(([name, age]) => ({name, age}));
console.log(people);
...or in ES5:
var s = 'Jack:13,Phil:15,Lucy:12'
var people = s.split(",")
.map(function(e) { return e.split(":"); })
.map(function(e) { return {name: e[0], age: e[1]}; });
console.log(people);
I'm not sure why I did two maps rather than just doing the second split and creating the object in the same callback; I guess I'm thinking more and more in a "functional programming" way. I'd change it, but Eddie's answer already does it in a single map, so...
...(edit) but since it looks like you wanted separate properties rather than using the person's name like Eddie did, here's an example of the above but with just a single map:
const s = 'Jack:13,Phil:15,Lucy:12'
const people = s.split(",")
.map(e => {
const [name, age] = e.split(":");
return {name, age};
});
console.log(people);
...or in ES5:
var s = 'Jack:13,Phil:15,Lucy:12'
var people = s.split(",")
.map(function(e) {
var parts = e.split(":");
return {name: parts[0], age: parts[1]};
});
console.log(people);

You can split() the string and use map() to loop thru the array. This will return an array of objects.
var s = 'Jack:13,Phil:15,Lucy:12';
var result = s.split(',').map(o => {
let [k, v] = o.split(':');
return {[k]: v};
});
console.log(result);
If you want a single object, you can use reduce
var s = 'Jack:13,Phil:15,Lucy:12';
var result = s.split(',').reduce((c, o) => {
let [k, v] = o.split(':');
return Object.assign(c, {[k]: v});
}, {});
console.log(result);

You can try with:
const result = s.split(',')
.map(value => value.split(':'))
.reduce((acc, [name, value]) => {
acc[name] = +value;
return acc;
}, {});
Output:
{
"Jack": 13,
"Phil": 15,
"Lucy": 12
}

As I'm sure you've worked out there are many ways to do this, I thought I'd add another method
let s = 'Jack:13,Phil:15,Lucy:12'
let obj = {};
s.split(",").forEach(part => {
obj[part.split(":")[0]] = part.split(":")[1];
})
console.log(obj);
This is a simple split the string and then on each item of the new array do a split and push the results into an empty object already declared.

You could split the parts and build a new object with key/value pairs.
var string = 'Jack:13,Phil:15,Lucy:12',
result = Object.assign(...string
.split(',')
.map(s => (([k, v]) => ({ [k]: v }))(s.split(':')))
);
console.log(result);
For getting an array with objects
var string = 'Jack:13,Phil:15,Lucy:12',
result = string
.split(',')
.map(s => (([name, age]) => ({ name, age }))(s.split(':')));
console.log(result);

Easy to do with .map():
var s = 'Jack:13,Phil:15,Lucy:12';
var items = s.split(',')
.map((entry) => entry.split(':'))
.map((item) => ({name: item[0], age: item[1]}));
console.log(items);

Related

Create new JSON string from array

Fairly new to JSON and I'm trying to get my head around conversions. I have an array:
['Role1', 'Role2', 'Role3']
and I'm trying to stringify it so that it reads as
{"Role1": true, "Role2": true, "Role3": true}
So far I've tried assigning the original array to an object and the calling stringify but I can't figure out how to add the boolean value in the string. Thanks in advance.
You'll have to create an intermediate reduce function to assign those values before converting to JSON.
const data = ['Role1', 'Role2', 'Role3']
const makeJson = () =>
JSON.stringify(data.reduce((a, c) => ({ ...a, [c]: true }), {}))
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
Is this what you need as output?
const arr = ['Role1', 'Role2', 'Role3']
const result = JSON.stringify(arr.reduce((a, n)=>{
return {
...a,
[n]: new Boolean(true).toString()
}
},{}))
console.log(result)
Another approach could be to combine Object.fromEntries with Array.prototype.map
const data = ['Role1', 'Role2', 'Role3']
const result = Object.fromEntries(data.map(s => [s, true]));
console.log(JSON.stringify(result));
This should do the trick:
let rolesArray = ['Role1', 'Role2', 'Role3'];
let rolesObject = {};
// iterate over roles to fill an object
rolesArray.forEach((role) => {
rolesObject[role] = true;
});
JSON.stringify(rolesObject) // Outputs the desired string
Or in a more concise way but less readable for a SO example :
JSON.stringify(rolesArray.reduce((o, s) => { o[s] = true; return o }, {}));
I have a preference for using the for-loop — still valid but other methods will be much short.
var array = ["Role1", "Role2", "Role3"],
json = {};
for (i = 0; i < array.length; i++) {
json[array[i]] = true;
}
console.log(json);
Use reduce() so we can set the value to true without a second loop
Using the spread operator (...) to merge the objects
const data = ['Role1', 'Role2', 'Role3'];
const obj = data.reduce((prev, cur) => ({ ...prev, [cur]: true }), {});
console.log(obj);
console.log(JSON.stringify(obj));
{
"Role1": true,
"Role2": true,
"Role3": true
}
{"Role1":true,"Role2":true,"Role3":true}
if you want to do that you must use code Below .
json-encode(Array)

I have two arrays and want to concat and send the data via post method

I have two arrays one is of keys and one is of its values
a=[name,place,job],
b=[John,Atlanta,Engineer]
I want to concat a and b and send it by post method like
xyz={
'name':'John',
'place:'Atlanta',
'job':'Engineer'
}
Working Demo
let a = ['name','place','job'];
let b = ['John','Atlanta','Engineer'];
let payload = a.reduce((obj, item, index) => (obj[item] = b[index], obj) ,{});
console.log(payload);
Service
this.http.post<any>(this.URL, payload);
You can iterate over an source array and then create a object with key and value then use Object.assign.
For ex:
a = ["name", "place", "job"];
b = ["John", "Atlanta", "Engineer"];
xyz = {};
constructor() {
this.a.forEach((item, index) => {
var obj = {
[this.a[index]]: this.b[index] || ""
};
Object.assign(this.xyz, obj);
});
console.log(this.xyz);
}
Working Demo
it is possible to use Object.assign and map methods:
let a = ['name','place','job'];
let b = ['John','Atlanta','Engineer'];
const result = Object.assign(...a.map((k, i) => ({[k]: b[i]})))
console.log(result);

What is a concise way to parse a javascript string that is a comma delimited list of key=value pairs?

I'm trying to parse a string into a JavaScript array or map. The string I'm trying to parse looks like:
"{key1=value1, key2=value2, key3=value3}"
The code I currently have works, but it's a bit lengthy.
str = "{key1=value1, key2=value2, key3=value3}";
str = str.replace(/{/g, '');
str = str.replace(/}/g, '');
var strMap = {};
str.split(', ').forEach(function(x) {
var arr = x.split('=');
strMap[arr[0]] = arr[1];
});
console.log(strMap)
That gets me what I want, but it's not very clean. Someone suggested I use JSON.parse, but it doesn't seem to work as the string isn't in valid JSON format.
Is there a concise way to do it so I'm not manually parsing the string?
You could split the string by comma and whitespace and splir key/value pairs for the properties of the new object. The result has strings as value.
const getPair = ([k, v]) => ({ [k]: v });
var string = "{key1=value1, key2=value2, key3=value3}",
result = Object.assign(...string
.slice(1, -1)
.split(/,\s+/)
.map(p => getPair(p.split('=')))
);
console.log(result);
Or take (upcoming) Object.fromEntries.
const getPair = ([k, v]) => ({ [k]: v });
var string = "{key1=value1, key2=value2, key3=value3}",
result = Object.fromEntries(string
.slice(1, -1)
.split(/,\s+/)
.map(p => p.split('='))
);
console.log(result);
You can use some ES6 features to pretty easily put together a decent naive solution (format as outlined by your example).
const example = "{key1=value1, key2=value2, key3=value3}";
const stripped = example.substring(1, example.length - 1);
const map = stripped.split(",")
.map(pair => pair.trim())
.reduce((result, current) => {
const [key, value] = current.split("=");
return {
...result,
key: value
};
}, {});

Lodash Group array of object and return array of key instead of object

I have an array of objects like this
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"}]
Using _.groupBy(data,"age") will return name as a key with array of object.
How do I return only array of name?
Use Array#reduce
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"}]
const res = data.reduce((a,{name,age})=>{
if(!a[age]) a[age] = [];
a[age].push(name);
return a;
}, {});
console.log(res);
UPDATE
Thanks for help , i need a key to be age and a value to be array of
only names instead of object , i have edited my question
In this case you can use reduce
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"},{name:'abc', age:'23'}]
const op = data.reduce((out,{name,age})=>{
if(out[age]){
out[age].push(name)
} else {
out[age] = [name]
}
return out
},{})
console.log(op)
Simply you can use map
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"}]
const op = data.map(({name}) => name)
console.log(op)
As #ori asking for unique names you can use Set if you want unique one only
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"},{name:'abc', age:'23'}]
const op = [...new Set(data.map(({name}) => name))]
console.log(op)
Use _.flow() to create a function that groups by age, then map the groups with _.mapValues(), and use _.map() to pluck the names from the arrays:
const { flow, groupBy, mapValues, map } = _
const fn = flow(
arr => groupBy(arr, 'age'),
groups => mapValues(groups, g => map(g, 'name'))
)
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"}]
const result = fn(data)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
And the terser lodash/fp version:
const { flow, groupBy, mapValues, map } = _
const fn = flow(
groupBy('age'),
mapValues(map('name'))
)
const data = [{name:"abc",age:"18"},{name:"dfd",age:"18"},{name:"dnss",age:"20"},{name:"dnnns",age:"12"}]
const result = fn(data)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
after grouping you need to iterate every group and return only name:
const res = _.chain(data)
.groupBy('age')
.mapValues(group => _.map(group, 'name'))
// or with FP .mapValues(_.partial(_.map, _, 'name'))
.value();

Transform from string array to hashmap in Lodash

What is the most precise way to transform from this
["access","edit","delete"]
to this
{access:true, edit:true, update:true}
Currently i loop to assign each value in object but i wonder if lodash already provide function for this
Use reduce(). This can all be done with a simple one-liner, that doesn't require any libraries:
const input = ["access","edit","delete"];
console.log(
input.reduce((obj, key) => { obj[key] = true; return obj; }, {})
);
With the new es6 spread syntax, you can even make this easier:
const input = ["access","edit","delete"];
console.log(
input.reduce((obj, key) => ({...obj, [key]: true}), {})
);
LODASH
You can map it to a array of entries and then simply use fromPairs of lodash
_.fromPairs(input.map(k=>[k, true]))
var input = ["access","edit","delete"];
var res = _.fromPairs(input.map(k=>[k,true]));
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
ES6
You can map your input to a key (your each input) value (true) pair of objects and assign them.
Object.assign( ...input.map(k=>({[k]: true})))
var input = ["access","edit","delete"]
var res = Object.assign( ...input.map(k=>({[k]: true})));
console.log(res);
In case you want a Map object you can map your input to entries (as used in lodash example) and simply construct a new Map like
new Map(input.map(k=>[k, true]))
No need to import a library for something so simple, just reduce the array of keys into an object indexed by those keys:
const input = ["access","edit","delete"];
const output = input.reduce((a, key) => Object.assign(a, {[key]: true}), {});
console.log(output);
Or, assigning to the property of the accumulator rather than using Object.assign:
const input = ["access","edit","delete"];
const output = input.reduce((a, key) => {
a[key] = true;
return a;
}, {});
console.log(output);
If you absolutely want to use lodash (As opposed to the above vanilla javascript reduce() answers), you can use _.mapValues() to accomplish this:
const input = ["access","edit","delete"];
const output = _.mapValues(_.keyBy(input), () => true)
console.log(output);
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.11/lodash.min.js" integrity="sha256-7/yoZS3548fXSRXqc/xYzjsmuW3sFKzuvOCHd06Pmps=" crossorigin="anonymous"></script>

Categories