I am having 2 element list which is like this,
a = ['first_name', 'user']
b = ['last_name', 'abcd']
I want to convert it into,
{
'first_name' : 'user',
'last_name' : 'abcd'
}
This is what I tried:
a = ['first_name', 'user']
b = ['last_name', 'abcd']
new_dict = {}
new_dict[a[0]] = a[1]
new_dict[b[0]] = b[1]
console.log(new_dict)
Are there any simple/native JS method than this?
You could place the a and b arrays in an outer array, and then reduce that array into a single object.
var o = [a,b].reduce(function(p, c) { p[c[0]] = c[1]; return p; }, {});
You can use Object.assign with map() and spread syntax.
var a = ['first_name', 'user'], b = ['last_name', 'abcd']
var obj = Object.assign({}, ...[a, b].map(([k, v]) => ({[k]: v})))
console.log(obj)
You could use Array#reduce with Object.assign and computed property names with a previous destructuring assignment.
var a = ['first_name', 'user'],
b = ['last_name', 'abcd'],
object = [a, b].reduce((r, [k, v]) => Object.assign(r, { [k]: v }), {});
console.log(object);
Related
I have an array like:
let arr = ['ABC', 'DEF']
And I'd like to transform that array to
let obj = {"ABC": 0, "DEF": 0}
What's the appropriate ES6 syntax to make that transformation?
let arr = ['ABC', 'DEF']
arr.reduce(x => ({[x] : 0 }))
This is close but I end up with {"ABC": 0}
Basically, I want to take an array of arbitrary length and assign all of the values in that array to a "default" value of 0.
Thanks!
Just use a plain, simple loop:
const arr = ['ABC', 'DEF'];
const obj = {};
for (const x of arr) obj[x] = 0;
If you want to get fancy, I'd recommend Object.fromEntries:
Object.fromEntries(arr.map(x => [x, 0]))
You are just making single objects like map. You need to keep returning the object.
const arr = ['ABC', 'DEF']
const result = arr.reduce((o, k) => ({[k] : 0, ...o }), {});
console.log(result)
const result2 = arr.reduce((o, k) => (o[k] = 0, o), {});
console.log(result2)
obj = arr.reduce((result, item, index) => {
result[item] = 0
return result
}, {})
Hopefully, this will help you. let me know if you have any issues.
You can just use Array.reduce and pass an empty object as the initial value like code below:
var arr = ["ABC","DEF"].reduce((a,b)=> (a[b]=0,a),{});
console.log(arr);
Suppose I have an object {'a':20,'b':6,'c':21,'d':12}
After getting sort by values in descending order,
The desired output : Keys: ['c','a','d','b'] and Values: [21,20,12,6]
How can I achieve that efficiently? I came to knew that we cannot we cant sort js object keys based on values, since the order of keys is random everytime.
I came to knew that we cannot we cant sort js object keys based on values, since the order of keys is random everytime.
That's not true (it's not random, and it's not different every time), but sorting JavaScript objects is almost never useful.
You have several options to get the array you've shown. One simple one is to use Object.entries to get an array of [key, value] arrays, then sort that, then get just the keys from it via map:
const obj = {'a':20,'b':6,'c':21,'d':12};
const keys = Object.entries(obj)
.sort(([k1, v1], [k2, v2]) => v2 - v1)
.map(([k, v]) => k);
console.log(keys);
Object.entries is relatively new, but easily polyfilled if needed.
If you need it in ES5 (with Object.entries polyfilled):
var obj = {'a':20,'b':6,'c':21,'d':12};
var keys = Object.entries(obj)
.sort(function(e1, e2) {
return e2[1] - e1[1];
})
.map(function(e) {
return e[0];
});
console.log(keys);
In a comment you've asked how to have the values in a separate array as well. You can either build that value array as a side-effect of map by pushing into it, like this:
const obj = {'a':20,'b':6,'c':21,'d':12};
const values = [];
const keys = Object.entries(obj)
.sort(([k1, v1], [k2, v2]) => v2 - v1)
.map(([k, v]) => {
values.push(v);
return k;
});
console.log(keys);
console.log(values);
...or if using map for side-effects bothers you (it's often not best practice), just use forEach (or for-of) instead:
const obj = {'a':20,'b':6,'c':21,'d':12};
const keys = [];
const values = [];
Object.entries(obj)
.sort(([k1, v1], [k2, v2]) => v2 - v1)
.forEach(([k, v]) => {
keys.push(k);
values.push(v);
});
console.log(keys);
console.log(values);
The for-of version:
const obj = {'a':20,'b':6,'c':21,'d':12};
const keys = [];
const values = [];
for (const [k, v] of Object.entries(obj).sort(([k1, v1], [k2, v2]) => v2 - v1)) {
keys.push(k);
values.push(v);
}
console.log(keys);
console.log(values);
(You might use a temporary variable for the result of .sort, then use for (const [k, v] of theTemporaryVariable) {.)
const obj = {'a':20,'b':6,'c':21,'d':12};
const result = Object.keys(obj)
.reduce((acc, key) => {
const value = obj[key];
acc.push({ key, value });
acc.sort((a, b) => b.value - a.value);
return acc;
}, []);
console.log(result);
output
[
{ key: 'c', value: 21 },
{ key: 'a', value: 20 }
{ key: 'd', value: 12 }
{ key: 'b', value: 6 }
]
Try this.
const list = {'a':20,'b':6,'c':21,'d':12};
let myObject = Object.fromEntries(Object.entries(list).sort( (a,b) => b[1] - a[1] ));
Object.prototype.mySplit = function() {
return Object.keys(this).map((key) => {
return {
key: key,
value: this[key]
};
});
}
let keys = [];
let values = [];
let properties = myObject.mySplit();
for (var i = 0; i < properties.length; i++) {
keys.push(properties[i]['key']);
values.push(properties[i]['value']);
}
console.log(keys);
console.log(values);
1) Get keys from an object
2) Sort keys based on val comparision
function cmp(a, b) {
return (a < b) ? 1 : (a > b) ? -1 : 0
}
function sortObj(obj) {
const keys = Object.keys(obj).sort((x,y) => cmp(obj[x],obj[y]))
const vals = keys.map(x => obj[x])
return {sortedKeys: keys, sortedValues: vals}
}
result = sortObj({'a':20,'b':6,'c':21,'d':12})
console.log(result)
Answer
{
sortedKeys: ["c", "a", "d", "b"]
sortedValues: [21, 20, 12, 6]
}
I have an array:
let arr = ["a=1", "b=22", "c=11"];
And I want to split the string inside array so it becomes an object later, which will look like:
{a: 1, b: 22, c: 11}
Can I somehow do that
You could split the string an map new objects. Later assign all objects to a single object.
var array = ["a=1", "b=22", "c=11"],
object = Object.assign(
...array.map(s => ((k, v) => ({ [k]: +v }))(...s.split('=')))
);
console.log(object);
you can use array.forEach, so you wont be creating an array instead you will iterate through the array, and you can take each item and split so it will create an array
like item = ["a", "1"], you can assign the key as a to the object which is the first index and value is second index,The value is string so you can convert to number and return it.
let arr = ["a=1", "b=22", "c=11"];
var obj = {}
arr.forEach(o => {
var item = o.split("=");
return obj[item[0]] = Number(item[1])
})
console.log("required obj", obj)
You can use array#map with Object.assign() to create your object. string#split each word on = and generate the object.
let arr = ["a=1", "b=22", "c=11"],
result = Object.assign(...arr.map(word => {
let [key,value] = word.split('=');
return {[key] : +value};
}));
console.log(result);
You can also use array#reduce.
let arr = ["a=1", "b=22", "c=11"],
result = arr.reduce((r,word) => {
let [key,value] = word.split('=');
r[key] = +value;
return r;
}, {});
console.log(result);
Here, try this
let arr = ["a=1", "b=22", "c=11"];
const obj = {}
arr.forEach(i => {
const splitted = i.split('=')
obj[splitted[0]] = splitted[1]
} )
console.log(obj)
I would like to create a JS function that transform a generic collection (an array or object of nested levels of arrays or objects) into an object that his keys are an input array argument (if provided, if not all distinct objects keys in input) and values are an array of leaf values for these keys in input). Leaf values can be distinct if flag provided.
Something like:
transform([{a:1, b:'1', c:true, d:1},{a:'1', b:2, c:3, d:false}, {a:1, c:'test'}], ['a','b','c'], true);
OR
transform({x:{b:2,c:{c:3, d:1}},b:'1',z:{b:2,c:true,a:1},a:'1',g:{c:'test',d:false}}, ['a','b','c'], true);
Will produce the same output:
{a:[1, '1'], b:['1', 2], c:[true, 3, 'test']}
First argument is the collection - mandatory
Second one is array of keys - optional
Third argument is the unique flag - optional
If second argument is omitted. It will produce this :
{a:[1, '1'], b:['1', 2], c:[true, 3, 'test'], d:[1,false]}
What is the fast and/or elegant way to do it?
Is there any lodash/underscore helper for it.
Thanks.
The basics
The main part of this problem is walking the object trees recursively and collecting the values.
To do so, we write a function that looks at a value and determines if it's an object. If it isn't, we concatenate the value to a results array. If it is, we reduce its values using the same logic.
const deepValues = (obj, res = []) =>
isObject(obj)
? Object.values(obj).reduce(flip(deepValues), res)
: res.concat(obj)
console.log(
deepValues({x:{b:2,c:{c:3, d:1}}})
);
// Utils
function flip(f) { return (x, y) => f(y, x) };
function isObject(x) { return Object.prototype.toString.call(x) === "[object Object]" };
Customizing it
Once you understand this function, adding the other bits and pieces makes a bit more sense.
Step 1: Not all the values...
So we want to concatenate the value to the results if its key matches our criterium.
We add a keyPred function to our signature and start working with [key, value] pairs rather than just the values. The predicate takes a key and returns a boolean that indicates if we should store it.
The function becomes a bit harder to read, but it's not that big of a difference from the initial one:
const certainDeepValues = (keyPred, obj, res = []) =>
Object.entries(obj)
.reduce((r, [k, v]) =>
isObject(v)
? certainDeepValues(keyPred, v, r)
: keyPred(k) ? r.concat(v) : r
, res);
console.log(
certainDeepValues(
k => k === "c",
{x:{b:2,c:{c:3, d:1}}}
)
);
// Utils
function isObject(x) { return Object.prototype.toString.call(x) === "[object Object]" };
Step 2: Only collect unique values
Javascript has the perfect type for a collection of unique values: a Set, which makes this a small change. The default argument is new Set and the concat method becomes add.
const certainDeepValues = (keyPred, obj, res = new Set()) =>
Object.entries(obj)
.reduce((r, [k, v]) =>
isObject(v)
? certainDeepValues(keyPred, v, r)
: keyPred(k) ? r.add(v) : r
, res);
console.log(
[...certainDeepValues(
k => k === "c",
{x:{b:2,c:{c:3, d:1, e: { c: "2" }}}, c: 3}
)]
);
// Utils
function flip(f) { return (x, y) => f(y, x) };
function isObject(x) { return Object.prototype.toString.call(x) === "[object Object]" };
Your own signature
Now, all there's left is to implement the desired signature. This is where it gets a bit ugly, but since you didn't post any attempts and merely wrote your "question" as an assignment to us, I'll leave it up to you to clean it up :)
const certainDeepValues =
(concat, keyPred, obj, res = new Set()) =>
Object.entries(obj)
.reduce((r, [k, v]) =>
isObject(v)
? certainDeepValues(concat, keyPred, v, r)
: keyPred(k) ? concat(r, k, v) : r
, res);
const transform = (xs = [], keys = [], uniquesOnly = false) => {
const keySet = new Set(keys);
const keyPred = keys.length
? k => keySet.has(k)
: k => true;
const concat = uniquesOnly
? (acc, k, v) => (acc[k] = (acc[k] || new Set()).add(v), acc)
: (acc, k, v) => (acc[k] = (acc[k] || []).concat(v), acc)
const unwrap = uniquesOnly
? acc => mapObj(s => [...s], acc)
: acc => acc;
return unwrap(xs.reduce(
(r, x) => certainDeepValues(concat, keyPred, x, r),
{}
));
};
console.log(
JSON.stringify(
transform([{a:1, b:'1', c:true, d:1},{a:'1', b:2, c:3, d:false}, {a:1, c:'test'}], ['a','b','c'], true)
)
);
console.log(
JSON.stringify(
transform([{x:{b:2,c:{c:3, d:1}},b:'1',z:{b:2,c:true,a:1},a:'1',g:{c:'test',d:false}}], ['a','b','c'], true)
)
);
console.log(
JSON.stringify(
transform([{x:{b:2,c:{c:3, d:1}},b:'1',z:{b:2,c:true,a:1},a:'1',g:{c:'test',d:false}}], undefined, true)
)
);
// Utils
function mapObj(f, obj) { return Object.assign({}, ...Object.entries(obj).map(([k, v]) => ({[k]: f(v)}))); }
function flip(f) { return (x, y) => f(y, x) };
function isObject(x) { return Object.prototype.toString.call(x) === "[object Object]" };
I have an array as such: [[1,3],[2,5],[1,3],[2,5]] and i would like to remove any duplicate sub-arrays. I tried using this code:
uniqueArray = array.filter(function(item, pos) {
return array.indexOf(item) == pos; });
It still returns true for all the cases.
Which function can i use to get the desired result.
Conver the 2D array into 1D array with stringified elements
Then put then into a Set to automatically filter out the repeating elements
Now convert the Set back to an array and map the array by JSON parsing each element to restore back the arrays.
Readable and no nested loops.
const arr = [[1,3],[2,5],[1,3],[2,5]];
const setArray = new Set(arr.map(x => JSON.stringify(x)))
const uniqArray = [...setArray].map(x => JSON.parse(x))
console.log(uniqArray)
Not the most efficient method, but the sub-arrays can be used as object keys:
a = [[1,3],[2,5],[1,3],[2,5]]
o = a.reduce((r, v) => (r[v] = v, r), {})
console.log(JSON.stringify( Object.values(o) ))
console.log(JSON.stringify( o ))
Update: seems a bit faster with numeric keys :
let a = [[1,3],[2,5],[1,3],[2,5]], t, b, n = _ => performance.now(),
v = Object.values, l = t => console.log(JSON.stringify(b), t)
t = n(); b = v(a.reduce((r, v) => (r[v] = v, r), {})) ; l(n() - t)
t = n(); b = v(a.reduce((r, v) => (r[v[0] + 1 / v[1]] = v, r), {})) ; l(n() - t)
t = n(); b = v(a.reduce((r, v) => (r[v[0] + 1 / v[1]] = v, r), new Map)); l(n() - t)
You can use Array#filter with an object that will store a hash for each iterated tuple:
var arr = [[1,3],[2,5],[1,3],[2,5]];
var result = arr.filter(function(t) {
var key = t.join('-');
return this[key] ? false : (this[key] = true);
}, Object.create(null));
console.log(result);