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);
Related
I have an array :
[
"2022-05-20",
"2022- 06-22",
"2022-06-20"
]
and I want to produce an object like this:
{
'2022-05-20': {disabled:true},
'2022-06-22': {disabled: true},
'2022-06-20': {disabled: true},
}
I tried using a for loop but it kept producing errors. Is this possible with javascript?
You can use Array#reduce as in the following demo. You can also use Array#map but you would have to use Object.fromEntries as well.
const input = [ "2022-05-20", "2022- 06-22", "2022-06-20" ],
output = input.reduce(
(prev,cur) =>
({...prev,[cur]:{disabled:true}}), {}
);
console.log( output );
USING Array#map ...
Here is how you can use Array#map:
const input = [ "2022-05-20", "2022- 06-22", "2022-06-20" ],
output = Object.fromEntries(
input.map(date => [date, {disabled:true}])
);
console.log( output );
Can do it:
let dates = [
"2022-05-20",
"2022- 06-22",
"2022-06-20"
];
let newObj = Object.assign(...dates.map(key => ({[key]: {disabled: true}})));
console.log(newObj)
This might get the job done.
const yourArray = ["2022-05-20", "2022-06-22", "2022-06-20"];
const obj = {};
for(const x of yourArray) obj[String(x)] = { disabled: true };
console.log(obj); // :)
Create the variable obj that is going to save the produced object you want. Iterating throw your array and using a string parsed version of the value in the current iteration (parsing just in case, if you already know the array is made of strings, this is kinda unnecessary) to save it as a key on the new object, also assigning to that key, the value { disabled: true }.
Here is a one liner solution:
let res = data.reduce((acc, curr) =>(acc[curr] = {disabled: true}, acc), {});
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);
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.
I have variable that contain array inside, when i was tried to print it with javascript console.log(res) show like this:
res = [{sakti: "23"},{Baim: "20"},{Jaka: "18"}]
How i suppose to do, if i want to change the data type into like this:
res = [{name: "sakti", y: 23},{name: "Baim", y: 20},{name: "Jaka", y: 18}]
my current code:
this.categoryservice.getRole().subscribe((res)=>{
console.log(res);
})
You can use map and Object.keys
let res = [{sakti: "23"},{Baim: "20"},{Jaka: "18"}]
let op = res.map(e=>{
let key = Object.keys(e)[0]
return { name: key, y: +e[key] }
})
console.log(op)
You can do this with Array.map, Object.entries and destructuring assignment:
const data = [{sakti: "23"}, {Baim: "20"}, {Jaka: "18"}];
const result = data.map(item => {
const [key, value] = Object.entries(item)[0];
return { name: key, y: value };
});
console.log(result);
Array.from is another way of mapping the object array into a new array of objects by using the second mapping argument. Object.keys & Object.values can be used to construct the new object by taking the [0] position from the key array which will be the name and [0] from the value array which will be the y key.
const res = [{sakti: "23"},{Baim: "20"},{Jaka: "18"}]
const arrayConv = Array.from(res, obj => { return {"name":Object.keys(obj)[0], "y":Object.values(obj)[0] } });
console.log(arrayConv);
you can use map and object.entries for this
var res = [{sakti: "23"},{Baim: "20"},{Jaka: "18"}]
var result = res.map((i)=>{
let obj = Object.entries(i);
return {'name': obj[0][0], 'y': obj[0][1]};
});
console.log(result);
With the new experimental flatMap() you can create a generic approach (in case one of your object have more than one key:val pair):
const res = [{sakti: "23", foo: "33"},{Baim: "20"},{Jaka: "18"}];
let mapped = res.flatMap(o => Object.entries(o).map(([k, v]) => ({name: k, y: +v})));
console.log(mapped);
But, you can always use reduce() for this too:
const res = [{sakti: "23", foo: "33"},{Baim: "20"},{Jaka: "18"}];
let mapped = res.reduce(
(acc, o) => acc.concat(Object.entries(o).map(([k, v]) => ({name: k, y: +v}))),
[]
);
console.log(mapped);
Assume , we have :
var all=[
{firstname:'Ahmed', age:12},
{firstname:'Saleh', children:5 }
{fullname: 'Xod BOD', children: 1}
];
The expected result is ['firstname','age', 'children', 'fullname']: the union of keys of all objects of that array:
all.map((e) => Object.keys(e) ).reduce((a,b)=>[...a,...b],[]);
This is work fine , However, i am seeking a solution more performance using directly reduce method without map , I did the following and it is failed.
all.reduce((a,b) =>Object.assign([...Object.keys(a),...Object.keys(b)]),[])
You can use Set, reduce() and Object.keys() there is no need for map.
var all=[
{firstname:'Ahmed', age:12},
{firstname:'Saleh', children:5 },
{fullname: 'Xod BOD', children: 1}
];
var result = [...new Set(all.reduce((r, e) => [...r, ...Object.keys(e)], []))];
console.log(result)
Here's a solution using generic procedures concat, flatMap, and the ES6 Set.
It's similar to #NenadVracar's solution but uses higher-order functions instead of a complex, do-it-all-in-one-line implementation. This reduces complexity in your transformation and makes it easier to re-use procedures in other areas of your program.
Not that ... spread syntax is bad, but you'll also notice this solution does not necessitate it.
var all = [
{firstname:'Ahmed', age:12},
{firstname:'Saleh', children:5 },
{fullname: 'Xod BOD', children: 1}
];
const concat = (x,y) => x.concat(y);
const flatMap = f => xs => xs.map(f).reduce(concat, []);
const unionKeys = xs =>
Array.from(new Set(flatMap (Object.keys) (xs)));
console.log(unionKeys(all));
// [ 'firstname', 'age', 'children', 'fullname' ]
Just out of curiosity, I've been benchmarking some solutions to your problem using different approaches (reduce vs foreach vs set). Looks like Set behaves well for small arrays but it's extremely slow for bigger arrays (being the best solution the foreach one).
Hope it helps.
var all = [{
firstname: 'Ahmed',
age: 12
}, {
firstname: 'Saleh',
children: 5
}, {
fullname: 'Xod BOD',
children: 1
}],
result,
res = {};
const concat = (x,y) => x.concat(y);
const flatMap = f => xs => xs.map(f).reduce(concat, []);
const unionKeys = xs =>
Array.from(new Set(flatMap (Object.keys) (xs)));
for(var i = 0; i < 10; i++)
all = all.concat(all);
console.time("Reduce");
result = Object.keys(all.reduce((memo, obj) => Object.assign(memo, obj), {}));
console.timeEnd("Reduce");
console.time("foreach");
all.forEach(obj => Object.assign(res, obj));
result = Object.keys(res);
console.timeEnd("foreach");
console.time("Set");
result = [...new Set(all.reduce((r, e) => r.concat(Object.keys(e)), []))];
console.timeEnd("Set");
console.time("Set2");
result = unionKeys(all);
console.timeEnd("Set2");
Try this code:
var union = new Set(getKeys(all));
console.log(union);
// if you need it to be array
console.log(Array.from(union));
//returns the keys of the objects inside the collection
function getKeys(collection) {
return collection.reduce(
function(union, current) {
if(!(union instanceof Array)) {
union = Object.keys(union);
}
return union.concat(Object.keys(current));
});
}