Convert object with multiple arrays to array of objects - javascript

I stuggle a lot with data I get from an API:
This is the way the data gets returned, the amout of arrays differs.
const objData = {
arr1: [1,2,3],
arr2: [1,2,1],
arr3: [2,1,2],
arr4: ["a","b", "c"]
}
This is the way it SHOULD look
const desired = [
{a: 1, b: 1, c: 2, d: "a"},
{a: 2, b: 2, c: 1, d: "b"},
{a: 2, b: 1, c: 2, d: "c"}
]
This gives me the desired result, but it is not dymanic, since I have to provide the names of the arrays, and the amount of arrays in the object is not allowed to change.
const DataObj = []
for (let i = 0; i < objData.arr1.length; i++) {
const objX = {
a: objData.arr1[i],
b: objData.arr2[i],
c: objData.arr3[i],
d: objData.arr4[i],
}
DataObj.push(objX)
}
Can anybody help me to solve this? How can I make this independent from the names of the arrays and the amount of arrays in the dataset?

You could map the arrays with new objects.
const
objData = { arr1: [1, 2, 3], arr2: [1, 2, 3], arr3: [2, 1, 2], arr4: ["a", "b", "c"] },
keys = { arr1: 'a', arr2: 'b', arr3: 'c', arr4: 'd' },
result = Object
.entries(objData)
.reduce((r, [key, array]) => array.map((v, i) => ({ ...r[i], [keys[key]]: v })), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Non functional approach, use integers to get your letters
const objData = {
arr1: [1, 2, 3, 5],
arr2: [1, 2, 1, 4],
arr3: [2, 1, 2, 3],
arr4: ["a", "b", "c", "d"]
}
const len = Object.values(objData)[0].length;
let cnt = 97;
let newObj = {};
const list = [];
for (let i = 0; i < len; i++) {
for (let key in objData) {
newObj[String.fromCharCode(cnt)] = objData[key][i];
++cnt
}
list.push(newObj);
cnt = 97;
newObj = {};
}
console.log(list)

Related

Merge objects from two arrays of object based in the index

i searched a lot about this but i do not find anything that can enlight me about my issue:
I have this code:
let array1 = ["a", "b", 3, {
p1: 'hola'
}, "c", "d"],
array2 = [1, 2, {
p1: 'adios'
}],
result = [],
i, l = Math.min(array1.length, array2.length);
for (i = 0; i < l; i++) {
if (typeof array1[i] === 'object' && typeof array2[i] === 'object') {
result.push(array2[i], ...(JSON.stringify() === JSON.stringify() ?
[] :
[array1[i]]
));
} else {
result.push(array2[i], array1[i]);
}
}
result.push(...array1.slice(l), ...array2.slice(l));
console.log(result);
i have modified the code with the suggestions, right now the code does this:
we have two array;
array1 = ["a", "b", 3, {p1: 'hello'},"c", "d"]
array2 = [1, 2, {p1: 'hello'}]
the result right now is this based in the code:
result: [1, 'a', 2, 'b', {p1: 'hello'}, 3, {p1: 'hello'}, 'c', 'd']
this work fine because i dont want to omit objects that are in different index between the two array, the problem right now is that when the objects in the two array are in the same index this code;
array1 = ["a", "b", {p2: 'goodbye'},"c", "d"]
array2 = [1, 2, {p1: 'hello'}]
result : [1, 'a', 2, 'b', {p1: 'hello'}, 'c', 'd']
This is my issue right now, what i want is that when there are object in the same index on two array compare the properties of the objects and is the same skip the first array object and pass the second to the final array, but if the properties are not the same, combine the properties of the object in one, this is the ideal result that i want:
array1 = ["a", "b", {p2: 'goodbye'},"c", "d"]
array2 = [1, 2, {p1: 'hello'}]
result : [1, 'a', 2, 'b', {p1: 'hello', p2: 'goodbye'}, 'c', 'd']
I think this is what you're after.
let array1 = ['a', 'b', { p2: 'goodbye' }, 'c', 'd'];
let array2 = [1, 2, { p1: 'hello' }];
let result = [];
for (let i = 0; i < Math.max(array1.length, array2.length); i++) {
if (typeof array1[i] == 'object' && typeof array2[i] == 'object') {
result.push({ ...array2[i], ...array1[i] });
} else {
array2[i] && result.push(array2[i]);
array1[i] && result.push(array1[i]);
}
}
console.log(result);
You could compare the items and if same omit the second item.
let array1 = ["a", "b", {p1: 'hello world'},"c", "d"],
array2 = [1, 2, {p1: 'hello world'}],
result = [],
i, l = Math.min(array1.length, array2.length);
for (i = 0; i < l; i++) {
result.push(array2[i], ...(JSON.stringify() === JSON.stringify()
? []
: [array1[i]]
));
}
result.push(...array1.slice(l), ...array2.slice(l));
console.log(result);

Create array of objects using arrays of values

I have fairly lot of data in this form
A B C D
-------
1 2 3 4
5 6 7 8
9 1 2 3
represented using javascript types as :
df = {A: [1,5,9], B: [2,6,1], C: [3,7,2], D:[4,8,3]}
I want to convert this into this form:
[{A:1, B:2, C:3, D:4}, {A:5, B:6, C:7, D:8}, {A:9, B:1, C:2, D:3}]
I tried implementing it as:
keyes = ["A", "B", "C", "D"]
getrow = (i) => Object.assign( ...keyes.map((k) => ({[k]: df[k][i]})))
df.A.map( (x,j) => getrow(j))
But this is slow for the size of the table I have. Is there any faster way to do this?
You could use reduce and forEach loops to create array of objects.
const df = {
A: [1, 5, 9],
B: [2, 6, 1],
C: [3, 7, 2],
D: [4, 8, 3]
}
const result = Object.keys(df).reduce((r, k) => {
df[k].forEach((e, i) => {
if (!r[i]) r[i] = {}
r[i][k] = e;
})
return r;
}, [])
console.log(result)
Or maybe for better performance you can go with the for loops.
const df = {
A: [1, 5, 9],
B: [2, 6, 1],
C: [3, 7, 2],
D: [4, 8, 3]
}
const result = [];
for (let key in df) {
for (let i = 0; i < df[key].length; i++) {
if (!result[i]) result[i] = {}
result[i][key] = df[key][i]
}
}
console.log(result)
You could take two for loops, and check the existence of the object at a certain index. Then assign the value to the property.
This version is faster than the use of array methods.
var data = { A: [1, 5, 9], B: [2, 6, 1], C: [3, 7, 2], D: [4, 8, 3] },
result = [],
key, values,
i;
for ([key, values] of Object.entries(data)) {
for (i = 0; i < values.length; i++) {
if (!result[i]) result[i] = {};
result[i][key] = values[i];
}
}
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Convert two arrays into an object

var foo = { "a": [1,2,3] }
var bar = { "b": [7,8,9] }
output should look like this
[ {a: 1, b: 7}, {a: 2, b: 8}, {a:3, b: 9}]
How can I do this using ramda or javascript functional programming ?
I have done this using for loop i = 0, is it possible using functional ramda programming
If both arrays are always the same length, you can do this using map.
function mergeArrays(arr1, arr2) {
return arr1.map(function(item, index) {
return {
a: arr1[index], //or simply, item
b: arr2[index]
};
});
}
var a = [1, 2, 3];
var b = [7, 8, 9];
var joined = mergeArrays(a, b);
document.getElementById('result').innerHTML = JSON.stringify(joined, null, 2);
<pre id="result">
</pre>
You can achieve this using R.transpose to convert an array of [[1,2,3], [7,8,9]] to [[1, 7], [2, 8], [3, 9]] and then map over it with R.zipObj.
const fn = R.compose(
R.map(R.zipObj(["a", "b"])),
R.transpose
)
const a = [1, 2, 3], b = [7, 8, 9]
const result = fn([a, b])
console.log(result)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
If you would prefer to pass a and b as two arguments to fn rather than an array then you can swap R.transpose in the example above with R.unapply(R.transpose).
Assuming you want [{a:1,b:7},{a:2,b:8},{a:3,b:9}] it can be done pretty easily with map using the index to get the value in b:
var result = a.map((v, i) =>({ a: v, b: b[i] }));
i am having an array
const peopleObject = { "123": { id: 123, name: "dave", age: 23 },
"456": { id: 456, name: "chris", age: 23 }, "789": { id: 789, name:
"bob", age: 23 }, "101": { id: 101, name: "tom", age: 23 }, "102":
{ id: 102, name: "tim", age: 23 } }
for this particular i have created a code that convrts array to object i hope this is usefull for you
const arrayToObject = (array) =>
array.reduce((obj, item) => {
obj[item.id] = item
return obj
}, {})
const peopleObject = arrayToObject(peopleArray)
console.log(peopleObject[idToSelect])
Your expected output doesn't have a valid format. You should store the data in array. Like ,
var output = [];
var a = [1,2,3], b = [7,8,9];
for(var i=0; i< a.length; i++){
var temp = {};
temp['a'] = a[i];
temp['b'] = b[i];
output.push(temp);
}
You cannot store the result in an object the way you want. Objects are key-value pairs. But what you expect is only the values without keys which is not possible!
create function form ramda's addIndex and map
const data = { keys: ['a', 'b', 'c'], values: ['11', '22', '33'] }
const mapIndexed = R.addIndex(R.map)
const result = mapIndexed((item, i) => {
return { [item]: data.values[i] }
}, data.keys)
You will get an array of objects

javascript pattern matching object

Given a javascript object array eg.
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}]
is there a faster way of getting all the b values from each object which meet a specific criteria such as a = 1 to return something like
b_consolidated = [2,3]
instead of looping through every object in the array?
You can use Array#filter function to get the items of your criteria, then use Array#map to get only b property.
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}];
let values = objArray.filter(item => item.a === 1).map(item => item.b);
console.log(values);
Or you can do this in one loop
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}];
let values = [];
objArray.forEach(item => {
if(item.a === 1) {
values.push(item.b);
}
});
console.log(values);
You could use Array#reduce in a single loop.
let array = [{ a: 1, b: 2, c: 3}, { a: 1, b: 3, c: 2 }, { a: 2, b: 5, c: 1 }],
result = array.reduce((r, o) => o.a === 1 ? r.concat(o.b) : r, []);
console.log(result);
Fastest version with for loop.
let array = [{ a: 1, b: 2, c: 3}, { a: 1, b: 3, c: 2 }, { a: 2, b: 5, c: 1 }],
i, l,
result = [];
for (i = 0, l = array.length; i < l; i++) {
if (array[i].a === 1) {
result.push(array[i].b);
}
}
console.log(result);
You only need to iterate over the array once, if you use reduce:
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}]
let result = objArray.reduce((arr, val) => {
if(val.a === 1)
arr.push(val.b);
return arr;
}, []);
console.log(result);
This is as fast as it'll get, short of a manual for loop:
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}]
let result = [];
for(var i = 0 ; i < objArray.length; i++){
if(objArray[i].a === 1)
result.push(objArray[i].b);
}
console.log(result);
Here's a JSPerf to illustrate the difference.
A manual for loop is by far the fastest.
More faster would be using .reduce
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}];
objArray.reduce(function(res,obj){
if(obj.a===1)
res.push(obj.b);
return res;
},[]);
// [2,3]
In Ramda
let objArray = [{a: 1, b: 2 , c:3},{a: 1, b:3, c:2},{a: 2, b:5, c:1}]
R.pipe(
R.filter(R.propEq('a', 1)),
R.pluck('b')
)(objArray)
// [2, 3]
Filter returns the array values matched by the condition.
Pluck returns a new list by plucking the same named property off all objects in the list supplied.
Edit 1:
Example of using the mentioned reduce pattern in Ramda:
R.reduce((acc, x) => R.ifElse(
R.propEq('a', 1),
(item) => R.pipe(R.prop('b'), R.append(R.__, acc))(item),
R.always(acc)
)(x), [])(objArray)
// [2, 3]

lodash multidimensional pluck

With the lodash library, I'd like to be able to pluck multiple values into a multi-dimensional array, along the lines of:
var arr = [{ a: 2, b: 3, c: 4 }, { a: 1, b: 4, c: 2 }];
_.pluck(arr, ['a', 'c']) --> [[2, 4], [1, 2]]
Is this possible?
Thanks.
There is no pluck on multiple keys, but you can do this:
_.map(['a', 'c'], function(path) {
return _.pluck(arr, path);
});
This will return values grouped by key.
Edit:
_.mpluck = function(collection, paths) {
return _.zip(
_.map(paths, function(path) {
return _.pluck(collection, path);
})
);
}
var arr = [{ a: 2, b: 3, c: 4 }, { a: 1, b: 4, c: 2 }];
_.mpluck(arr, ['a', 'c']) --> [[2, 4], [1, 2]]
this will replace each object by an array of the specified keys.
Without lodash:
function mpluck(collection, paths) {
return collection.map(function(obj) {
return paths.map(function(path) {
return obj[path];
});
});
}
Solution without lodash:
function pluck(arr, k) {
return arr.reduce(function (r, a) {
r.push(k.reduce(function (rr, aa) {
rr.push(a[aa]);
return rr;
}, []));
return r;
}, []);
}
var arr = [{ a: 2, b: 3, c: 4 }, { a: 1, b: 4, c: 2 }],
x = pluck(arr, ['a', 'c']);
document.write('<pre>' + JSON.stringify(x, 0, 4) + '</pre>');

Categories