Converting object values and properties into an array - javascript

How to convert an object with names and values into an array of object just like the below format.
'result' : { "name1" : "Angle", "name2" : "Demon", "name3" : "Hunter"}
Desired output :
"result" : [
{'name1' : 'Angle'},
{'name2' : 'Demon'},
{'name3' : 'Hunter'}
]

You can use Object.entries and Array#map methods as follows:
const input = {'result' : { "name1" : "Angle", "name2" : "Demon", "name3" : "Hunter"}}
const output = [input].map(
({result}) =>
({result: Object.entries(result).map(([k,v]) => ({[k]:v}))})
)[0];
console.log( output );

const result = { "name1" : "Angle", "name2" : "Demon", "name3" : "Hunter"};
const res = Object.keys(result).map(item => {
const obj = {};
obj[item] = result[item]
return obj;
});
console.log(res);

Using Object.entries:
const input = { "name1": "Angle", "name2": "Demon", "name3": "Hunter" };
const result = Object.entries(input).map(([k, v]) => ({ [k]: v }));
console.log(result);
Using Object.keys:
const input = { "name1": "Angle", "name2": "Demon", "name3": "Hunter" };
const result = Object.keys(input).map(k => ({ [k]: input[k] }));
console.log(result);
A breakdown of the syntactic gymnastics of the arrow function given to map.
Notice where we have:
.map(([k, v]) => ({ [k]: v })
Basically, each element of the array returned by Object.entries is itself an array with two values, the first is the property name (key) and the second is the property value. For this example, Object.entries(input) returns:
[
[ "name1", "Angle" ],
[ "name2", "Demon" ],
[ "name3", "Hunter" ]
]
But we want to turn ["name1", "Angle"] into an object like { name1: "Angle" }.
The most straightforward way of expressing this would be:
Object.entries(input).map(entry => {
return { [entry[0]]: entry[1] };
}
The only tricky part in the syntax above is creating a dynamic property name based on a variable with the syntax { [key]: value }. We want a property named entry[0] with the value in entry[1] and { [entry[0]]: entry[1] } will do that.
But we can make use of some destructuring and return the object from the arrow function directly.
destructuring. Rather than using entry as the parameter, we can destructure this short 2-element array into the key and value immediately. Although it's tempting to write [k, v] => you must enclose it in parentheses like ([k, v]) => .
returning an object from an arrow function. It's also tempting to return an object literal like => { name1: "Angle" } but again, that's ambiguous (looks like a code block) so we have to enclose the object literal with parentheses: => ({ name1: "Angle" })
All those extra parentheses are unfortunately necessary. The whole thing looks like:
Object.Entries(input).map(([k, v]) => ({ [k]: v }));
So perhaps you may find the destructuring syntax is clunky because of the parentheses. Instead you can use Object.keys. Object.keys(input) returns:
[
"name1",
"name2",
"name3"
]
We can map each property name to the desired object like this .map(k => ({ [k]: input[k] })) Which saves us a little bit of destructuring syntax awkwardness at the cost of having to specify the array by its name again.
This is likely the fastest way, if the number of properties is large, because it should use fewer allocations and intermediate objects.
Alternate approach with a loop
There is another way, using a loop, and it's faster than both of the above if the number of properties is very small.
const input = { "name1": "Angle", "name2": "Demon", "name3": "Hunter" };
const result = [];
for (let key in input) result.push({ [key]: input[key] });
console.log(result);
(This actually performs best on your tiny test data, I found.)
But I personally prefer functional constructs over imperative constructs because it gives the compiler the opportunity to do something more efficient than a loop. I believe we should teach the next generation of programmers to embrace modern ways of describing programs, and loops are passé in that regard.

Using Object.fromEntries and Object.entries
const input = { "name1": "Angle", "name2": "Demon", "name3": "Hunter" };
const result = Object.entries(input).map((ent) => Object.fromEntries([ent]));
console.log(result);

Related

How to change the object key from nested array object and return array object

I have an array arr1 and an object arr2 with a nested config array.
If the object of arr1 has a key that matches with an id in that nested config and deeper questions array, then change that key (in the arr1 object) with the title property that is found next to that id.
Here is an example. The key isWorking from arr1 is the same as arr2.config[0].questions[0].id value, so
change that isWorking key to the value found in arr2.config[0].questions[0].custom.title.
var arr1= [
{"jobs": "Marketing","isWorking": yes,"country": "MY"},
{"country": "IN","members": 4}
]
var arr2=
{
"id":1,
"name":"xxx",
"config":[
{
"questions":[
{
"id":"isWorking",
"custom":{
"title":"Are you working?"
}
},
{
"id":"jobs",
"custom":{
"title":"Please specify job(s)"
}
}
]
},
{
"questions":[
{
"id":"country",
"custom":{
"title":"which Country?"
}
},
{
"id":"members",
"type":"choices",
"custom":{
"title":"How many members?"
}
}
]
}
]
}
Expected output:
[
{"Please specify job(s)": "Marketing","Are you working": yes,"which Country": "MY"},
{"which Country": "IN","How many members": 4}
]
I tried:
var result = arr1.map(e => ({
arr2.config.find(i => {
i.questions.find( q => {
q.id === Object.key(e) ? Object.key(e) === q.custom.title : q.id
}
})
}))
In your code the find callbacks do not return anything. When you have a code block (with braces) you need a return statement. Also, the outer object literal which you have as the return value of the map callback cannot have just the find call in it. It should have the proper object literal syntax, like with spread syntax. Moreover, the find method can only return an existing object, not a new, modified one.
I will assume here that the matching strings for the first object have to be found in the first questions array, and for the second object in the second questions array.
I also propose to rename arr2, because it isn't an array. It is a plain object, with a property that is an array (config).
Here is how you could do it with Object.fromEntries and Object.entries:
const arr1 = [{"jobs": "Marketing","isWorking": "yes","country": "MY"}, {"country": "IN","members": 4}];
const obj = {"id":1,"name":"xxx","config":[{"questions":[{"id":"isWorking","custom":{"title":"Are you working?"}},{"id":"jobs","custom":{"title":"Please specify job(s)"}}]},{"questions":[{"id":"country","custom":{"title":"which Country?"}},{"id":"members","type":"choices","custom":{"title":"How many members?"}}]}]}
const result = arr1.map((e, i) => Object.fromEntries(
Object.entries(e).map(([key, value]) =>
[obj.config[i].questions.find(({id}) =>
key === id
)?.custom?.title ?? key, value]
)
))
console.log(result);

Returning all key:value pairs from object array that key includes underscore in javascript

I have rows that contain data in form like this:
{
id:"id",
param:"street1",
param:"street2",
param_eu:"street",
param_ru:"street",
},
{
id:"id2",
param:"street1",
param:"street2",
param_fr:"street",
param_cz:"street",
},
I would like to pick only pairs that contain "_" and only keep the country as key name, like this:
{
eu:"street",
ru:"street"
},
{
fr:"street",
cz:"street"
},
Managed to get it done with multiple inner for loops but that is huge. Any better solutions?
You can first use .map() on your array to map each object to a new object. The new objects are created using Object.fromEntries(), Object.entries(), .filter() and .map(). You can use these methods as follows:
Use Object.entries() to obtain an array of [[key, value],...] pairs from your object.
On the above key-value pair array, use .filter() to obtain only the keys that contain an underscore in them by checking if the key includes an underscore "_"
Once you have filtered your array, use .map() on your filtered key-value array to map each inner array (ie: [key, value]) to a new array, where everything to the left of the underscore is removed. To do this, you can split your key using "_" to form an array of two parts - the "param" & the alpha country code. You can use .pop() to obtain the last string in your array of parts (ie: the alpha country code)
Wrap this filtered/mapped array of key-value pairs in a call to Object.fromEntries(). Since this takes an array of [[key, value], ...] pairs, it will be able to build an object for you, where each inner [key, value] array is converted into a {key: value, ...} in the resulting object.
See example below:
const arr = [{ id: "id", param: "street1", param: "street2", param_eu: "street", param_ru: "street", }, { id: "id2", param: "street1", param: "street2", param_fr: "street", param_cz: "street", } ];
const res = arr.map(
obj => Object.fromEntries(
Object.entries(obj).filter(
([key]) => key.includes("_")
).map(([key, val])=> [key.split("_").pop(), val])
)
);
console.log(res);
You can iterate over the list, and every time, reduce the object properties:
const data = [
{ id:"id", param:"street1", param:"street2", param_eu:"street", param_ru:"street" },
{ id:"id2", param:"street1", param:"street2", param_fr:"street", param_cz:"street" }
];
// iterate over objects
const res = data.reduce((countries, item) => {
// reduce object properties
const itemWithCountries = Object.entries(item)
.reduce((acc, [key, value]) => {
if(key.includes('_')) acc[key.split('_').pop()] = value;
return acc;
}, {});
// push reduced object
if(Object.keys(itemWithCountries).length > 0) countries.push(itemWithCountries);
return countries;
}, []);
console.log(res);
You could map new object by getting all entries from the objects, get the one you want and build object from the entries as new objects.
const
array = [{ id: "id", param: "street1", param: "street2", param_eu: "street", param_ru: "street" }, { id: "id2", param: "street1", param: "street2", param_fr: "street", param_cz: "street" }],
result = array.map(object => Object.fromEntries(Object
.entries(object)
.filter(([key]) => key.includes('_'))
));
console.log(result);

Array value to properties name javascript

Is there a one-line way to transform array value to the properties name of an object?
Example:
var arr = ['name', 'age', 'size'];
To
{'name' :null, 'age':null, 'size':null}
Actually I'm processing like this:
var arr = ['name', 'age', 'size'];
let obj = {};
arr.map(z => obj[z] = null);
I suppose that is the shortest way but I'm not sure.
Use reduce:
arr.reduce((prev, curr) => {
return Object.assign(prev, {[curr]: null})
}, {})
or you can one-line it if you want, but imo it looks worse then:
arr.reduce((prev, curr) => Object.assign(prev, {[curr]: null}), {})
Note, that Object.assign is a better way to code this, rather than using spread operator ({... }).
Spread operator creates a NEW object every loop. This can lead to big performance issues.
Object.assign on the other hand works on the first object.
reduce could turn it into a one-liner:
var obj = arr.reduce((acc, curr)=> ({...acc, [curr]: null}),{})
You can use Array.prototype.reduce method to convert an array to another type
var arr = ["name", "age", "size"];
let output = arr.reduce((accumulator, current) => {
return {...accumulator, [current]: null}
}, {})
console.log(output);

Rename keys with ramda js

const orignalArr = [
{
personName: 'Joe'
}
]
expected output:
const convertedArr = [
{
name: 'Joe'
}
]
I'm thinking the renamed keys are defined in an object (but fine if there's a better way to map them):
const keymaps = {
personName: 'name'
};
How can I do this with Ramda?
Something with R.map
There is an entry in Ramda's Cookbook for this:
const renameKeys = R.curry((keysMap, obj) =>
R.reduce((acc, key) => R.assoc(keysMap[key] || key, obj[key], acc), {}, R.keys(obj))
);
const originalArr = [{personName: 'Joe'}]
console .log (
R.map (renameKeys ({personName: 'name'}), originalArr)
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
But with the ubiquity of ES6, it's pretty easy to write this directly:
const renameKeys = (keysMap) => (obj) => Object.entries(obj).reduce(
(a, [k, v]) => k in keysMap ? {...a, [keysMap[k]]: v} : {...a, [k]: v},
{}
)
You can combine Ramda with Ramda Adjunct. Using the renameKeys (https://char0n.github.io/ramda-adjunct/2.27.0/RA.html#.renameKeys) method is very useful. With it you can simply do something like this:
const people = [
{
personName: 'Joe'
}
]
const renameKeys = R.map(RA.renameKeys({ personName: 'name' }));
const __people__ = renameKeys(people);
console.log(__people__) // [ { name: 'Joe' }]
Hope it helped you :)
This is my take on renameKeys. The main idea is to separate the keys and values to two array. Map the array of keys, and replace with values from keyMap (if exist), then zip back to object:
const { pipe, toPairs, transpose, converge, zipObj, head, map, last } = R
const renameKeys = keysMap => pipe(
toPairs, // convert to entries
transpose, // convert to array of keys, and array of values
converge(zipObj, [ // zip back to object
pipe(head, map(key => keysMap[key] || key)), // rename the keys
last // get the values
])
)
const originalArr = [{ personName: 'Joe', lastName: 'greg' }]
const result = R.map(renameKeys({ personName: 'name' }), originalArr)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
My idea to make it is to first check that the old prop I want to rename exists, and the new key I want to create doesn’t.
Then, I will use the S_ common combinator to make it point-free.
Find JS common combinators here
const {
allPass, assoc, compose: B, complement, has, omit, prop, when
} = require('ramda');
const S_ = (f) => (g) => (x) => f (g (x)) (x);
const renameKey = (newKey) => (oldKey) => when(allPass([
has(oldKey)
, complement(has)(newKey)
]))
(B(omit([oldKey]), S_(assoc(newKey))(prop(oldKey))))
const obj = { fullname: 'Jon' };
renameKey('name')('fullname')(obj) // => { name: ‘Jon’ }
Here is my own solution, not too many arrow functions (just one), mostly pure Ramda calls. And it is one of shortest, if not the shortest ;)
First, based on your example
const { apply, compose, either, flip, identity, map, mergeAll, objOf, prop, replace, toPairs, useWith } = require('ramda');
const RenameKeys = f => compose(mergeAll, map(apply(useWith(objOf, [f]))), toPairs);
const originalArr = [
{
personName: 'Joe',
},
];
const keymaps = {
personName: 'name',
};
// const HowToRename = flip(prop)(keymaps); // if you don't have keys not specified in keymaps explicitly
const HowToRename = either(flip(prop)(keymaps), identity);
console.log(map(RenameKeys(HowToRename))(originalArr));
Second option, using any arbitrary lambda with renaming rules:
const { apply, compose, map, mergeAll, objOf, replace, toPairs, useWith } = require('ramda');
const RenameKeys = f => compose(mergeAll, map(apply(useWith(objOf, [f]))), toPairs);
const HowToRename = replace(/(?<=.)(?!$)/g, '_'); // for example
console.log(RenameKeys(HowToRename)({ one: 1, two: 2, three: 3 }));
Yields
{ o_n_e: 1, t_w_o: 2, t_h_r_e_e: 3 }
Third, you can use object-based rename rules from the first example and use fallback strategy, e.g. replace like in the second example, instead of identity.

Javascript Reduce Challenge, Getting the value of an Obj's Key

I'm following a course online and one of the challenges is this:
Write a function called extractKey which accepts two parameters, an array of objects, and the name of a key and returns an array with just the values for that key: You must use reduce.
extractKey([{name: "Elie", isInstructor:true},{name: "Tim", isInstructor:true},{name: "Matt", isInstructor:true}], "name");
// ["Elie", "Tim", "Matt"]
I thought I could do something like this:
function extractKey(arr, key) {
arr.reduce(function(a, b) {
console.log(a.push(b[key]))
}, [])
}
But its returning 1. I have a general idea of pushing each value into the empty array, but when console logging each value, a will return undefined at the next accumulator.
If you have to use reduce then I'd combine it with concat like this.
var arr = [{
name: "Elie",
isInstructor: true
}, {
name: "Tim",
isInstructor: true
}, {
name: "Matt",
isInstructor: true
}]
function extractKeys(array, key) {
return array.reduce((acc, obj) => {
return acc.concat(obj[key])
}, [])
}
console.log(extractKeys(arr, 'name'))
If you use reduce (not really neccessary here), you need to pass on the accumulator:
function extractKey(arr, key) {
arr.reduce(function(acc, el) {
console.log(a.push(el[key]))
return acc; // <--
}, [])
}
Alternatively a good old for loop might be easier to understand:
function extractKey(arr, key){
const result = [];
for(const el of arr)
result.push(el[key]);
return result;
}
Finally you also might use map instead and currying to beautify it:
const extract = key => obj => obj[key];
const result = original.map(extract("name"));
you were very close but with reduce you have to return the value after every iteration of your callback since only the accumulator's value is saved
function extractKey(arr, key) {
arr.reduce(function(a, b) {
a.push(b[key])
console.log(a)
return a;
}, []);
}

Categories