I have an data in an array that looks like that:
let data = {[val1, val2, val3], [val4, val5, val6]}
I need to convert it to a map with predefined keys:
let keys = [key1, key2, key3]
I would like my output to be key-value map like this:
0: {key1:value1, key2:value2, key3:value3}
1: {key1:value4, key2:value5, key3:value6}
I tried:
let obj = Object.assign(keys, data)
But output is:
0: (3) [value1, value2, value3]
1: (3) [value4, value5, value6]
Use Object.fromEntries and map
const data = [
[1, 2, 3],
[4, 5, 6]
];
const keys = ["key1", "key2", "key3"];
const updated = data.map(arr =>
Object.fromEntries(arr.map((item, i) => [keys[i], item]))
);
console.log(updated);
You can make use of .map() and .reduce() functions to get the desired output:
let data = [['val1', 'val2', 'val3'], ['val4', 'val5', 'val6']];
let keys = ['key1', 'key2', 'key3'];
let result = data.map(
vals => vals.reduce((r, c, i) => (r[keys[i]] = vals[i], r), {})
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Simple solution.
let data = [
[1, 2, 3],
[4, 5, 6]
];
let keys = ["key1", "key2", "key3"];
const res = data.map(([v1, v2, v3]) => {
return {
[keys[0]]: v1,
[keys[1]]: v2,
[keys[2]]: v3
};
});
console.log(res);
// Also
const res2 = data.map(arr => {
let map = {};
keys.forEach((key, index) => {
map[key] = arr[index];
});
return map;
});
console.log(res2);
// Also
const res3 = data.map(arr =>
keys.reduce((o, key, index) => {
o[key] = arr[index];
return o;
}, {})
);
console.log(res3);
.as-console-wrapper { max-height: 100% !important; top: 0; color: blue; background: #fff}
Related
Hi,
I have these 2 arrays of objects:
const arr1 = [{"id":"pear","qty":2},{"id":"apple","qty":2}];
const arr2 = [{"id":"pear","qty":5},{"id":"lemon","qty":1}];
I want to combine them but at the same time summing their values in qty when they have the same id so this is the expected output:
[{"id":"pear","qty":7},{"id":"apple","qty":2},{"id":"lemon","qty":1}];
I tried this but it only keeps the first object:
const newArray = arr1.map((obj) => {
const secondArrayObj = arr2.find((obj2) => obj2.id === obj.id);
if (secondArrayObj) {
return {...secondArrayObj, ...obj}
}
return null;
}).filter((obj) => obj != null);
console.log(newArray);
What is the best approach here?
Thank you.
For your code,the reason is that you are using Array.map(),it will only covnert arr1 to another array,and will not merge arr2
To solve it,we can do it via Array.reduce() and Array.filter()
const arr1 = [{"id":"pear","qty":2},{"id":"apple","qty":2}];
const arr2 = [{"id":"pear","qty":5},{"id":"lemon","qty":1}];
let arr3 = [...arr1,...arr2]
arr3 = arr3.reduce((a,v) => {
let obj = a.find(i => i.id === v.id)
if(obj){
obj.qty += v.qty
}else{
a.push(v)
}
return a
},[])
console.log(arr3)
There are several ways to skin the cat. Here is one that uses an intermediate sums object, which performs well with large arrays:
const arr1 = [{"id":"pear","qty":2},{"id":"apple","qty":2}];
const arr2 = [{"id":"pear","qty":5},{"id":"lemon","qty":1}];
let sums = {};
arr1.concat(arr2).forEach(obj => {
if(!sums[obj.id]) {
sums[obj.id] = 0;
}
sums[obj.id] += obj.qty;
});
let arr3 = Object.keys(sums).map(id => { return {id: id, qty: sums[id]}; });
console.log(arr3);
Output:
[
{
"id": "pear",
"qty": 7
},
{
"id": "apple",
"qty": 2
},
{
"id": "lemon",
"qty": 1
}
]
Combine both arrays
Reduce them to a map keyed by id and value being the sum of qty
Turn that object back into an array using Object.entries()
Map that back to an array of objects
const arr1 = [{"id":"pear","qty":2},{"id":"apple","qty":2}];
const arr2 = [{"id":"pear","qty":5},{"id":"lemon","qty":1}];
const newArray = [
...arr1
.concat(arr2)
.reduce(
(map, { id, qty }) => map.set(id, qty + (map.get(id) ?? 0)),
new Map()
),
].map(([id, qty]) => ({ id, qty }));
console.log(newArray);
.as-console-wrapper { max-height: 100% !important; }
I have an Object like this:
const val = {"abc":{"1":1, "2":6,"3":5},"def":{"1":3, "2":4,"3":8},"xyz":{"1":5, "2":6,"3":7}}
I want to transform the object data like below:
[{"abc":1,"def":3,"xyz":5},{"abc":6,"def":4,"xyz":6}, ...]
All the values are dynamic, any number of inner object may be there
I have tried like this:
const val = {"abc":{"1":1, "2":6,"3":5},"def":{"1":3, "2":4,"3":8},"xyz":{"1":5, "2":6,"3":7}}
let dataObj = {};
let secondArr = [];
let dataArr =[]
Object.entries(val).map(firstObj=>{
Object.entries(firstObj[1]).forEach(secondObj => {
dataObj={[firstObj[0]]:secondObj[1]};
secondArr.push(dataObj);
})
dataArr.push(secondArr)
})
console.log(dataArr)
Can anyone tell me a solution for this?
Thanks in advance
You could iterate the entries of the objects and take the inner keys as indices of the array with new objects with outer key and value.
var data = { abc: { 1: 1, 2: 6, 3: 5 }, def: { 1: 3, 2: 4, 3: 8 }, xyz: { 1: 5, 2: 6, 3: 7 } },
result = Object
.entries(data)
.reduce((r, [k, o]) => {
Object.entries(o).forEach(([i, v]) =>
Object.assign(r[i - 1] = r[i - 1] || {}, { [k]: v }));
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I´m trying to update the object atribute:
data : [
{"id":1,"rp":"2426","cr":"11-11"},
{"id":1,"rp":"1119","cr":"19-21"},
{"id":1,"rp":"3453","cr":"23-81"}
]
new object would be updated as below.
NewData: [
{"id":1,"rp":"2426","cr":"11/11"},
{"id":1,"rp":"1119","cr":"19/21"},
{"id":1,"rp":"3453","cr":"23/81"}
]
I looking to update the object cr atribute for all values, for example using javascript.replace() method, I would do replace("-","/").
That's just a simple usage of Array#map and String#replace:
ES2018
const data = [{"id":1,"rp":"2426","cr":"11-11"},{"id":1,"rp":"1119","cr":"19-21"},{"id":1,"rp":"3453","cr":"23-81"}]
const r = data.map(({ cr, ...rest }) => ({ cr: cr.replace('-', '/'), ...rest }));
console.log(r);
You could use map method to create new array and replace to update cr property.
var data = [{"id":1,"rp":"2426","cr":"11-11"},{"id":1,"rp":"1119","cr":"19-21"},{"id":1,"rp":"3453","cr":"23-81"}]
var update = data.map(({cr, ...rest}) => ({...rest, cr: cr.replace("-","/")}))
console.log(update)
You could iterate and map the array.
var data = [{ id: 1, rp: "2426", cr: "11-11" }, { id: 1, rp: "1119", cr: "19-21" }, { id: 1, rp: "3453", cr: "23-81" }],
newArray = data.map(o => Object.assign({}, o, { cr: o.cr.replace("-","/") }));
console.log(newArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can try this
let data = [
{"id":1,"rp":"2426","cr":"11-11"},
{"id":1,"rp":"1119","cr":"19-21"},
{"id":1,"rp":"3453","cr":"23-81"}
];
let newData = data.map(e=>{
e.cr = e.cr.replace(/-/, '/')
return e
})
console.log(newData)
Just try below
data.forEach(function(object){
object["cr"] = object["cr"].replace("-","/");
});
Try this:
const data = [
{"id":1,"rp":"2426","cr":"11-11"},
{"id":1,"rp":"1119","cr":"19-21"},
{"id":1,"rp":"3453","cr":"23-81"}
];
const newData = data.map(item => ({...item, cr: item.cr.replace(/-/g, '/')}));
console.log(newData);
If you need it to work in IE11:
const data = [
{"id":1,"rp":"2426","cr":"11-11"},
{"id":1,"rp":"1119","cr":"19-21"},
{"id":1,"rp":"3453","cr":"23-81"}
];
const newData = data.map(
function(item) {
return {
id: item.id,
rp: item.rp,
cr: item.cr.replace(/-/g, '/')
}
}
);
console.log(newData);
const data = [{"id":1,"rp":"2426","cr":"11-11"},{"id":1,"rp":"1119","cr":"19-21"},{"id":1,"rp":"3453","cr":"23-81"}]
const r = JSON.parse(JSON.stringify(data).replace(/-/g,'/'))
console.log(r);
existingJsObj = {"a": [1,2,3,4], "b":[11,22,33,44]}
I want to convert this javascript into something that doesnt have array items in it, like below
desiredJsObj = [{"a":1, "b":11},{"a":2,"b":22},{"a":3, "b":33},{"a":4, "b":44}]
You could iterate the keys and the values while using a new array and object for the result.
var object = { a: [1, 2, 3, 4], b: [11, 22, 33, 44] },
array = Object.keys(object).reduce(function (r, k) {
object[k].forEach(function (v, i) {
(r[i] = r[i] || {})[k] = v;
});
return r;
}, []);
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I would do following:
const income = {"a": [1,2,3,4], "b":[11,22,33,44]};
const res = income.a.map((a, i) => ({ a: a, b: income.b[i] }));
This works in assumption that "a" length is equal to "b" length.
try this
existingJsObj = {"a": [1,2,3,4], "b":[11,22,33,44]}
desiredJsObj = []
keys = Object.keys(existingJsObj);
existingJsObj[keys[0]].forEach((val, index) => {
value = {};
keys.forEach((key, i) => value[key] = existingJsObj[key][index])
desiredJsObj.push(value)
})
I have:
var keys = [ "height", "width" ];
var values = [ "12px", "24px" ];
And I'd like to convert it into this object:
{ height: "12px", width: "24px" }
In Python, there's the simple idiom dict(zip(keys,values)). Is there something similar in jQuery or plain JavaScript, or do I have to do this the long way?
The simplest ES6 one-liner solution using Array reduce:
const keys = ['height', 'width'];
const values = ['12px', '24px'];
const merged = keys.reduce((obj, key, index) => ({ ...obj, [key]: values[index] }), {});
console.log(merged);
Simple JS function would be:
function toObject(names, values) {
var result = {};
for (var i = 0; i < names.length; i++)
result[names[i]] = values[i];
return result;
}
Of course you could also actually implement functions like zip, etc as JS supports higher order types which make these functional-language-isms easy :D
use lodash.
_.zipObject
Example
_.zipObject(['a', 'b'], [1, 2]);
// ➜ { 'a': 1, 'b': 2 }
As an alternate solution, not already mentioned I think :
var result = {};
keys.forEach((key, idx) => result[key] = values[idx]);
You can combine two arrays with map method, then convert it with Object.fromEntries.
var keys = ["height", "width"];
var values = ["12px", "24px"];
var array = keys.map((el, i) => {
return [keys[i], values[i]];
});
// → [["height", "12px"], ["width", "24px"]]
var output = Object.fromEntries(array);
// → {height: "12px", width: "24px"}
console.log(output);
A functional approach with immutability in mind:
const zipObj = xs => ys => xs.reduce( (obj, x, i) => ({ ...obj, [x]: ys[i] }), {})
const arr1 = ['a', 'b', 'c', 'd']
const arr2 = ['e', 'f', 'g', 'h']
const obj = zipObj (arr1) (arr2)
console.log (obj)
You could use a reduce() function to map the key-value pairs to an object.
/**
* Apply to an existing or new object, parallel arrays of key-value pairs.
*
* #param {string[]} keys - List of keys corresponding to their accociated values.
* #param {object[]} vals - List of values corresponding to their accociated keys.
* #param {object} [ref={}] - Optional reference to an existing object to apply to.
*
* #returns {object} - The modified or new object with the new key-value pairs applied.
*/
function toObject(keys, vals, ref) {
return keys.length === vals.length ? keys.reduce(function(obj, key, index) {
obj[key] = vals[index];
return obj;
}, ref || {}) : null;
}
var keys = [ "height" , "width" ];
var values = [ "12px" , "24px" ];
document.body.innerHTML = '<pre>' + JSON.stringify(toObject(keys, values), null, 2) + '</pre>';
Here's an example with all consts (non-modifying) and no libraries.
const keys = ["Adam", "Betty", "Charles"];
const values = [50, 1, 90];
const obj = keys.reduce((acc, key, i) => {
acc[key] = values[i];
return acc;
}, {});
console.log(obj);
Alternatively, if you'd consider libraries you could use lodash zipobject which does just what you asked.
Now we have Object.fromEntries we can do something like that:
const keys = [ "height", "width" ];
const values = [ "12px", "24px" ];
const myObject = Object.fromEntries(
values.map((value, index) => [keys[index], value])
);
console.log(myObject);
You could transpose the arrays and get the object with the entries.
const
transpose = (r, a) => a.map((v, i) => [...(r[i] || []), v]),
keys = [ "height", "width" ],
values = [ "12px", "24px" ],
result = Object.fromEntries([keys, values].reduce(transpose, []));
console.log(result);
function combineObject( keys, values)
{
var obj = {};
if ( keys.length != values.length)
return null;
for (var index in keys)
obj[keys[index]] = values[index];
return obj;
};
var your_obj = combine( your_keys, your_values);
Here's one which will transform nested arrays into an array of multiple key-value objects.
var keys = [
['#000000', '#FFFFFF'],
['#FFFF00', '#00FF00', '#00FFFF', '#0000FF'],
];
var values = [
['Black', 'White'],
['Yellow', 'Green', 'Cyan', 'Blue'],
];
const zipObj = xs => ys => xs.reduce( (obj, x, i) => ({ ...obj, [x]: ys[i] }), {})
var array = keys.map((el, i) => zipObj (keys[i]) (values[i]));
console.log(array);
Output is
[
{
"#000000": "Black",
"#FFFFFF": "White"
},
{
"#FFFF00": "Yellow",
"#00FF00": "Green",
"#00FFFF": "Cyan",
"#0000FF": "Blue"
}
]
Providing a solution with a for...of loop.
var keys = ["height", "width"];
var values = ["12px", "24px"];
const result = {};
for (let [index, key] of keys.entries())
result[key] = values[index];
console.log(result);
You can also use a library like ramda which has zipObj function.
Example:
const keys = ["height", "width"];
const values = ["12px", "24px"];
const result = R.zipObj(keys, values);
console.log(result);
In the jQuery-Utils project, the ArrayUtils module has a zip function implemented.
//...
zip: function(object, object2, iterator) {
var output = [];
var iterator = iterator || dummy;
$.each(object, function(idx, i){
if (object2[idx]) { output.push([i, object2[idx]]); }
});
return output;
}
//...