There is an array of objects
[
{a:1,val:[11,12]},
{a:9,val:[21,22]},
{a:7,val:[31,32]},
{a:8,val:[41,42]}
]
I am trying to convert it into:
[ [{a:1,val:11},{a:9,val:21},{a:7,val:31},{a:8,val:41}] ,
[{a:1,val:12},{a:9,val:22},{a:7,val:32},{a:8,val:42}]
]
How can I use underscore.js chain/map/pluck etc... function to get the flatten result in specified format in the cleanest way?
You could use Array#forEach and build the nested parts upon.
var data = [{ a: 1, val: [11, 12] }, { a: 9, val: [21, 22] }, { a: 7, val: [31, 32] }, { a: 8, val: [41, 42] }],
result = [];
data.forEach(function (a, i) {
a.val.forEach(function (b, j) {
result[j] = result[j] || [];
result[j][i] = { a: a.a, val: b };
});
});
console.log(result);
You can use array's reduce like this
var data = [
{a:1,val:[11,12]},
{a:9,val:[21,22]},
{a:7,val:[31,32]},
{a:8,val:[41,42]}
]
var result = data.reduce((res, next) => {
res[0].push({a: next.a, val: next.val[0]});
res[1].push({a: next.a, val: next.val[1]});
return res;
}, [[], []])
console.dir(result)
I have done as you have requested but used plain ES6 instead of underscore.
var restructure = (x)=>
[x.map(({a,val})=>({a,val:val[0]})),x.map(({a,val})=>({a,val:val[1]}))]
var result = restructure([
{a:1,val:[11,12]},
{a:9,val:[21,22]},
{a:7,val:[31,32]},
{a:8,val:[41,42]}
])
//[[{"a":1,"val":11},{"a":9,"val":21},{"a":7,"val":31},{"a":8,"val":41}],[{"a":1,"val":12},{"a":9,"val":22},{"a":7,"val":32},{"a":8,"val":42}]]
Here's a solution using underscore:
var result = _.chain(data)
.map(item => _.map(item.val, val => ({a: item.a, val})))
.unzip()
.value();
var data = [
{a:1,val:[11,12]},
{a:9,val:[21,22]},
{a:7,val:[31,32]},
{a:8,val:[41,42]}
]
var result = _.chain(data)
.map( item => _.map(item.val, val => ({a: item.a, val})))
.unzip()
.value();
document.getElementById('result').textContent = JSON.stringify(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.2/underscore.js"></script>
<p>
<pre id="result"></pre>
</p>
Related
I have an array of objects as the following;
[{"A":"34"},{"B":"13"},{"C":"35"},{"D":"74"}]
If the key is A, it's value has to be multiply by 30,B by 10,C by 5,D by 2. I would like to calculate the total sum after the multiplication;
34*30 + 13*10 + 35*5 + 74*2
Is there a way to achieve this other than an if/else statement? Thanks!
Reduce the array, and get the key / value pair by destructuring the array produce by calling Object.entries() on the each item. Get the value of the key, multiply by current value, and add to the accumulator.
const multi = { A: 30, B: 10, C: 5, D: 2 }
const fn = arr =>
arr.reduce((acc, item) => {
const [[k, v]] = Object.entries(item)
return acc + multi[k] * v
}, 0)
const arr = [{"A":"34"},{"B":"13"},{"C":"35"},{"D":"74"}]
const result = fn(arr)
console.log(result)
let input = [{"A": "34"}, {"B": "13"}, {"C": "35"}, {"D": "74"}];
let multiply = {A: 30, B: 10, C: 5, D: 2};
let result = input.reduce((sum, v) =>
sum + Object.values(v)[0] * multiply[Object.keys(v)[0]], 0);
console.log(result);
You can easily achieve this using Object.entries
const arr = [{ A: "34" }, { B: "13" }, { C: "35" }, { D: "74" }];
const multiplier = {
A: 30,
B: 10,
C: 5,
D: 2,
};
const result = arr.reduce((acc, curr) => {
const [[key, value]] = Object.entries(curr);
return acc + multiplier[key] * parseInt(value);
}, 0);
console.log(result);
You can create an dictionary to get the number with which the value should be multiplied as shown :
{"A":30, "B":13, "C":35, "D":74}
Now you can loop through your array of objects, and fetch the value from the dictionary using the key of the object:
const myArray = [{"A":"34"},{"B":"13"},{"C":"35"},{"D":"74"}]
const Nums = {"A":30, "B":10, "C":5, "D":2};
let Result = 0;
myArray.forEach((item)=>{
const key = Object.keys(item)[0];
var temp= parseInt(item[key]);
Result += temp*Nums[key];
})
console.log(Result);
Not sure how you map your values so that "A" === 30. But assuming you have a map:
const map = {
"A": 30,
"B": 10,
"C": 5,
"D": 2
}
const array = [{"A":"34"},{"B":"13"},{"C":"35"},{"D":"74"}];
Then in one line:
const outcome = array.map(element => map[Object.keys(element)[0]] * Object.values(element)[0]).reduce((acc, init) => acc + init, 0)
I have 2 array, one for key and other for value.
Want create new array with these arrays.
key: [01, 02, 03]
value: ["hi", "hello", "welcome"]
Output I need:
[
{"key": "1","value":"hi"},
{"key": "2","value":"hello"},
{"key": "3","value":"welcome"}
]
How to get result by this way.?
My code:
output = key.map(function(obj, index){
var myObj = {};
myObj[value[index]] = obj;
return myObj;
})
Result:
[
{"1","hi"},
{"2","hello"},
{"3","welcome"}
]
const keys = [01, 02, 03];
const values = ['hi', 'hello', 'welcome'];
const res = keys.map((key, ind) => ({ 'key': ''+key, 'value': values[ind]}));
console.log(res);
There is also a proposal for the following method of Object, fromEntries, which will do exactly what you want to, but it is not supported yet by the major browsers:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries
var myArray = [];
var keys = [45, 4, 9];
var cars = ["Saab", "Volvo", "BMW"];
cars.forEach(myFunction);
var txt=JSON.stringify(myArray);
document.getElementById("demo").innerHTML = txt;
function myFunction(value,index,array) {
var obj={ key : keys[index], value : value };
myArray.push(obj);
}
<p id="demo"></p>
You could take an object with arbitrary count of properties amd map new objects.
var key = [1, 2, 3],
value = ["hi", "hello", "welcome"],
result = Object
.entries({ key, value })
.reduce((r, [k, values]) => values.map((v, i) => Object.assign(
{},
r[i],
{ [k]: v }
)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here you have another apporach using reduce():
let keys = [01, 02, 03];
let values = ['hi', 'hello', 'welcome'];
let newArray = keys.reduce((res, curr, idx) => {
res.push({'key': curr.toString(), 'value': values[idx]});
return res;
}, []);
console.log(newArray);
Currently I'm getting data in the format below:
arr=[
0: {abc:1},
1: {efg:2},
2: {hij:3}
]
I need it in below format:
arr=[
{name:'abc', value:1},
{name:'efg', value:2},
{name:'hij', value:3}]
Assuming an arr has a following structure, it's only a matter of mapping through it and separating key and value:
var arr = [
{abc:1},
{efg:2},
{hij:3}
]
var result = arr.map(o => {
var k = Object.keys(o)[0];
return {
name: k,
value: o[k]
};
});
console.log(result);
var arr = [ {abc:1}, {efg:2},{hij:3}],
var arr1=[];
_.forEach(arr, function (val, key) {
_.forIn(val, function (val, key) {
arr1.push({ name: key, value: val });
})
});
console.log(arr1);
});**Implemented using loadash**
I want to transform this to an array of objects ordered based on an array of keys:
{
tom: 11,
jim: 22,
jay: 13
}
Input -> Output examples:
['jim', 'tom', 'kim', 'jay'] -> [{jim: 22}, {tom: 11}, {jay: 13}]
['may', 'jay', 'tom', 'jim'] -> [{jay: 13}, {tom: 11}, {jim: 22}]
How can I accomplish this? I'd rather a one line lodash solution.
For what it is worth, here's a JS function that performs what you want.
function transform(targetObj, keyArray) {
let resultArray = [];
// Sanity (may want to throw error here)
if (!targetObj || !keyArray) { return resultArray; }
for (let i = 0; i < keyArray.length; i++) {
if (!targetObj.hasOwnProperty(keyArray[i])) { continue; }
let item = {};
item[keyArray[i]] = targetObj[keyArray[i]];
resultArray.push(item);
}
return resultArray;
}
Tests
let obj = { tom: 11, jim: 22, jay: 13 };
let input1 = ['jim', 'tom', 'kim', 'jay'];
let input2 = ['may', 'jay', 'tom', 'jim'];
let result1 = transform(obj, input1);
console.log(JSON.stringify(result1));
let result2 = transform(obj, input2);
console.log(JSON.stringify(result2));
JSFiddle
Assuming the object is named obj and the list of keys to look up is named keys:
_.zip([keys, keys.map(x => obj[x])]).filter(([k, v]) => v).map(x => _.fromPairs([x]))
Or, if you don't care about order, there's another way:
_.toPairs(obj).filter(([k, v]) => _.include(keys, k)).map(x => _.fromPairs([x]))
A one-liner lodash solution would be to use lodash#toPairs to convert the object into an array of key-value pairs, lodash#chunk to wrap each pairs with another array as preparation for mapping each item to form the pairs into an object using lodash#map with a lodash#fromPairs iteratee.
var result = _(data).toPairs().chunk().map(_.fromPairs).value();
var data = {
tom: 11,
jim: 22,
jay: 13
};
var result = _(data).toPairs().chunk().map(_.fromPairs).value();
console.log(result);
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
An Vanilla JS ES6 solution would be to use Object#keys to get an array of keys from the object, Array#map to map each keys to associate each key to form an array of objects. We used the ES6 computed property names feature to associate the keys directly into an anonymous object.
var result = Object.keys(data).map(key => ({ [key]: data[key] }));
var data = {
tom: 11,
jim: 22,
jay: 13
};
var result = Object.keys(data).map(key => ({ [key]: data[key] }));
console.log(result);
.as-console-wrapper{min-height:100%;top:0}
If the browsers that you use doesn't support ES6 then you can simply convert the solution above into this:
var result = Object.keys(data).map(function(key) {
var object = {};
object[key] = data[key];
return object;
});
var data = {
tom: 11,
jim: 22,
jay: 13
};
var result = Object.keys(data).map(function(key) {
var object = {};
object[key] = data[key];
return object;
});
console.log(result);
.as-console-wrapper{min-height:100%;top:0}
Basically for a one liner solution to this you don't need lodash, just simple filter and map would be enough, however if you want you can use lodash.
//this is your source object
var keys = {
tom: 11,
jim: 22,
jay: 13
}
Now, Lets assume you have 2 (some) arrays
var input1 = ['jim', 'tom', 'kim', 'jay'];
var input2 = ['may', 'jay', 'tom', 'jim'];
And here we go:
//for first input
input1.filter(s=>keys[s]).map(s=> ({[s]: keys[s]}));
//for secondinput
input2.filter(s=>keys[s]).map(s=> ({[s]: keys[s]}));
Here is a working snippet for you:
var keys = {
tom: 11,
jim: 22,
jay: 13
}
var input1 = ['jim', 'tom', 'kim', 'jay'];
var input2 = ['may', 'jay', 'tom', 'jim'];
var output1 = input1.filter(s=>keys[s]).map(s=> ({[s]: keys[s]}));
var output2 = input2.filter(s=>keys [s]).map(s=> ({[s]: keys[s]}));
console.log("Output1: ", JSON.stringify(output1));
console.log("Output2: ", JSON.stringify(output2));
I need to transmit some data, that has too many key-value pairs.
As the keys are similar, I dont want to transmit them with each object.
Consider I have the following data:
[
{
x:11,
y:12
},{
x:21,
y:22
},{
x:31,
y:32
},{
x:41,
y:42
}
];
And I need the final output as
[ [x,y],[[11,12],[21,22],[31,32],[41,42]] ] OR
[ [x,y],[11,12],[21,22],[31,32],[41,42] ]
On the other end, I should be able to convert back to its original form.
It would be great if it can handle an additional key in some of the objects
I think I have seen lodash or underscore function for something close/similar to this, but I'm not able to find it right now.
NOTE: I don't know what the keys will be
Lodash v4.17.1
modify original
var modifiedOriginal = _.chain(original)
.map(_.keys)
.flatten()
.uniq()
.thru(function(header){
return _.concat(
[header],
_.map(original, function(item) {
return _.chain(item)
.defaults(_.zipObject(
header,
_.times(_.size(header), _.constant(undefined))
))
.pick(header)
.values()
.value()
})
);
})
.value();
modified back to original (keys order is not
guarantee)
var backToOriginal = _.map(_.tail(modified), function(item) {
return _.chain(_.head(modified))
.zipObject(item)
.transform(function(result, val, key) {
if (!_.isUndefined(val)) {
result[key] = val;
}
})
.value();
});
JSFiddle code https://jsfiddle.net/wa8kaL5g/1/
Using Array#reduce
var arr = [{
x: 11,
y: 12
}, {
x: 21,
y: 22
}, {
x: 31,
y: 32
}, {
x: 41,
y: 42
}];
var keys = Object.keys(arr[0]);
var op = arr.reduce(function(a, b) {
var arr = keys.reduce(function(x, y) {
return x.concat([b[y]]);
}, [])
return a.concat([arr]);
}, [keys]); //If all the objects are having identical keys!
console.log(JSON.stringify(op));
A little more verbose way of doing it:
[Edit: added the function to convert it back]
function convert(arr) {
var retArr = [ [/* keys (retArr[0]) */], [/* values (retArr[1]) */] ]
arr.forEach(function(obj){
// create new array for new sets of values
retArr[1].push([])
// put all of the keys in the correct array
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
// does the key exist in the array yet?
if (retArr[0].indexOf(key) === -1) {
retArr[0].push(key)
}
// get last index of retArr[1] and push on the values
retArr[1][retArr[1].length - 1].push(obj[key])
}
}
})
return retArr
}
function reConvert(arr) {
var retArr = []
var keys = arr[0]
arr[1].forEach(function(itemArr){
var obj = {}
itemArr.forEach(function(item, i){
obj[keys[i]] = item
})
retArr.push(obj)
})
return retArr
}
var objArr = [
{
x:11,
y:12
},{
x:21,
y:22
},{
x:31,
y:32
},{
x:41,
y:42
}
]
var arrFromObj = convert(objArr)
var objFromArr = reConvert(arrFromObj)
console.log(arrFromObj)
console.log(objFromArr)
A solution using Underscore.
First work out what the keys are:
var keys = _.chain(data)
.map(_.keys)
.flatten()
.uniq()
.value();
Then map across the data to pick out the value for each key:
var result = [
keys,
_.map(data, item => _.map(keys, key => item[key]))
];
and back again:
var thereAndBackAgain = _.map(result[1], item => _.omit(_.object(result[0], item), _.isUndefined));
Lodash's version of object is zipObject and omit using a predicate is omitBy:
var thereAndBackAgain = _.map(result[1], item => _.omitBy(_.zipObject(result[0], item), _.isUndefined));
var data = [
{
x:11,
y:12,
aa: 9
},{
x:21,
y:22
},{
x:31,
y:32,
z: 0
},{
x:41,
y:42
}
];
var keys = _.chain(data)
.map(_.keys)
.flatten()
.uniq()
.value();
var result = [
keys,
_.map(data, item => _.map(keys, key => item[key]))
];
var thereAndBackAgain = _.map(result[1], item => _.omit(_.object(result[0], item), _.isUndefined));
console.log(result)
console.log(thereAndBackAgain)
<script src="
https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
In ES6 you can do it by reducing it with Object.values(), and Object.keys(). You can restore it using a combination of Array.prototype.map() and Array.prototype.reduce():
const convertStructure = (data) => data.reduce((s, item) => {
s[1].push(Object.values(item));
return s;
}, [Object.keys(data[0]), []]); // all objects should be the same, so we can take the keys from the 1st object
const restoreStructure = ([keys, data]) => data.map((item) => item.reduce((o, v, i) => {
o[keys[i]] = v;
return o;
}, {}));
const data = [{
x: 11,
y: 12
}, {
x: 21,
y: 22
}, {
x: 31,
y: 32
}, {
x: 41,
y: 42
}];
const convertedStructure = convertStructure(data);
console.log('convertedStructure:\n', convertedStructure);
const restoredStructure = restoreStructure(convertedStructure);
console.log('restoredStructure:\n', restoredStructure);