array of objects manipulation in js - javascript

I have an array of object as below.
data: [ {col: ['amb', 1, 2],} , {col: ['bfg', 3, 4], },]
From above, I need to get array of array as below.
[ [{a: 'amb',b: [1], c: 'red'}, {a: 'amb',b: [2], c: 'orange'}],
[{a: 'bfg',b: [3], c: 'red'}, {a: 'bfg',b: [4], c: 'orange'}]
]
My attempt is as below.
let arrInner: Array<any> = []
let arrOuter: Array<Array<any>> = []
_.forEach(data, (item, i) => {
//create two objects redObj and orangeObj
redObj = {
a: item.col[0].toString(),
b: [item.col[1] as number],
c: 'red'
}
orangeObj = {
a: item.col[0].toString(),
b: [item.col[2] as number],
c: 'orange'
}
//put those two objects to array
arrInner.push(redObj)
arrInner.push(orangeObj)
//assign that array to another array
arrOuter[i] = arrInner
})
But when I print the arrOuter, it is not my expected output. Where I was wrong and how can I fix this?

You need to create a new arrInner each time through the forEach loop. Then push that onto arrOuter.
let arrOuter: Array <Array <any>> = []
_.forEach(data, (item, i) => {
//create two objects redObj and orangeObj
redObj = {
a: item.col[0].toString(),
b: [item.col[1] as number],
c: 'red'
}
orangeObj = {
a: item.col[0].toString(),
b: [item.col[2] as number],
c: 'orange'
}
//put those two objects to array
let arrInner = [redObj, orangeObj]
//assign that array to another array
arrOuter.push(arrInner)
})

Related

JavaScript, split object in 2, and push in array

I have an array of objects like this:
const arrayOfObjects = [
{ A: 1, B: 2, C: 3 },
{ A: 3, B: 4, C: 1 }
]
And another array which is called "headers"
const headers = [
['A', 'B'],
['C']
]
I have to create an array similar to the first one but, with those objects splited by what headers have in it's arrays.
This should be the goal:
const result = [
[
{ A: 1, B: 2 },
{ C: 3 }
],
[
{ A: 3, B: 4 },
{ C: 1 }
]
]
I tried by doing a "base" array with:
const baseArray = []
headers.forEach((header) => {
const objFromHeader = {};
header.forEach((head) => {
objFromHeader[head] = 0;
});
baseArray.push(objFromHeader);
});
That will give me the result array but with 0 values for each key.
And then loop for the first array and put inside another array the base array with the correct values.
Then I wanted to fill each key according to the value that comes from arrayOfObjects but here is where I can't see how could I loop that array of objects and put the correct value. The only problem with that approach is that the result array will have some 0 values that come from the initiation array that I'm using, it would be better to me to only put the objects that actually have values and not 0 (I was thinking on another function to delete those keys with value = 0...)
How could I achieve it in a better way?
Fiddle:
https://jsfiddle.net/pmiranda/Lpscz6vt/
When iterating over an object, use findIndex on the headers to identify which index in the headers array the property being iterated over should go into. Create an object there if it doesn't exist yet, and set the property.
const arrayOfObjects = [
{ A: 1, B: 2, C:3 },
{ A: 3, B: 4, C:1 }
];
const headers = [
['A', 'B'],
['C']
];
const toResultItem = (object) => {
const resultItem = [];
for (const [key, value] of Object.entries(object)) {
const headersIndex = headers.findIndex(arr => arr.includes(key));
resultItem[headersIndex] ??= {};
resultItem[headersIndex][key] = value;
}
return resultItem;
};
console.log(arrayOfObjects.map(toResultItem));
const arrayOfObjects = [
{ A: 1, B: 2, C: 3 },
{ A: 3, B: 4, C: 1 },
];
const headers = [['A', 'B'], ['C', 'D']];
const result = arrayOfObjects.map((obj) =>
headers.map((header) =>
header.reduce((acc, key) => {
acc[key] = obj[key];
return Object.keys(acc).reduce((newAcc, key) => {
if (acc[key]) {
newAcc[key] = acc[key];
}
return newAcc;
}
, {});
}, {})
)
);
console.log(result);
Array.forEach implementation
Logic
Loop through arrayOfObjects array.
Inside that, loop through headers array.
Inside that, loop through each array in the headers array.
Create an empty object and assign the property from nodes in headers array with values from objects in arrayOfObjects array.
const arrayOfObjects = [
{ A: 1, B: 2, C: 3 },
{ A: 3, B: 4, C: 1 }
];
const headers = [
['A', 'B'],
['C']
];
const baseArray = []
arrayOfObjects.forEach((obj) => {
const childNode = [];
headers.forEach((head) => {
const node = {};
head.forEach((key) => node[key] = obj[key]);
childNode.push(node);
});
baseArray.push(childNode);
});
console.log(baseArray)
Array.map and Array.reduce implementation.
Using the same logic implementes in the above solution, we can rewrite this using Array.map and Array.reduce as below.
const arrayOfObjects = [
{ A: 1, B: 2, C: 3 },
{ A: 3, B: 4, C: 1 }
];
const headers = [
['A', 'B'],
['C']
];
const output = arrayOfObjects.map((obj) => {
return headers.map((header) => {
return header.reduce((acc, curr) => {
acc[curr] = obj[curr];
return acc;
}, {});
})
})
console.log(output);

How to remove object properties from nested arrays of objects?

I am trying to remove these 2 properties from each object in the array while it's not working. Each object is inside an array. I mean The main array contains arrays of objects. Is there an easy way to solve it without using the map() twice? And how to return the main modified array in that case?
const modifiedItems = this.items.map(item => {
delete item.created,
delete item.removed
return item
})
Data looks like this:
this.items = [
[{ removed: 1, created: 1, a:2, b: 2, c: 3}]
[{ removed: 1, created: 1, a:2, b: 2, c: 3}, { removed: 1, created: 1, a:2, b: 2, c: 3},]
];
The above code doesn't work because it doesn't map to arrays inside the main array. How is the best to delete those properties from each object of all arrays located in the main array?
Instead of deleting, why not just return an object without the properties you want to remove.
You could destructure the properties you want to remove and then collect other properties in a variable using the rest parameters syntax. After this, you just need to return the variable which contains all the properties other than the ones you want to remove.
const modifiedItems = this.items.map(
({ created, removed, ...rest }) => rest
);
Following code snippet shows an example:
const arr = [
{ removed: 1, created: 1, a:2, b: 2, c: 3},
{ removed: 1, created: 1, a:2, b: 2, c: 3},
{ removed: 1, created: 1, a:2, b: 2, c: 3},
];
const modifiedItems = arr.map(
({ created, removed, ...rest }) => rest
);
console.log(modifiedItems);
Edit:
In your case, this.items is an array that contains nested arrays. So to remove the properties from the objects inside the nested arrays, you need to map over each nested array as well.
Following code snippet shows an example:
const items = [
[ { removed: 1, created: 1, a: 2, b: 2, c: 3 } ],
[
{ removed: 1, created: 1, a: 2, b: 2, c: 3 },
{ removed: 1, created: 1, a: 2, b: 2, c: 3}
]
];
const modifiedItems = items.map(subArr => {
return subArr.map(({ created, removed, ...rest }) => rest)
});
console.log(modifiedItems);

How to convert an array containing arrays of objects to single array witht hose object using Ramda expressions?

I am having a difficult time, there is some bad mapping going on on my code.
I have an array containing array of objects like that :
[
[{a: 1, b: 2},{a: 1, b: 3} ],
[{a: 5, b: 2},{a: 2, b: 5}]
]
And I want to make like that :
[
{a: 1, b: 2},
{a: 1, b: 3},
{a: 5, b: 2},
{a: 2, b: 5}
]
In order to do that, I thought I found the magical solution, make things flat, using flatten function, it was not working ( this problem is just a piece of code in a lot of code ) and I was wondering why, i wasted some time to find that this the problem, it is not the behovior I am expecting, as you can see in the image, the first thing I have is an array containing an array having two objects, with flatten method, I was expecting an array of two objects, but I am getting what you see in the image :
The code I have ttried is this :
const expectedArray = R.flatten(myArrayOfArraysOfObjects);
Full example :
const singleTronconPoints = troncon => {
return troncon.geometri_linestring;
};
console.log('troncons : ');
console.log(troncons);
console.log('map troncons points');
console.log(map(singleTronconPoints, troncons));
console.log('flatten');
console.log(flatten(map(singleTronconPoints, troncons)));
and this is full result :
How can I solve that, is there another magical ( :P ) solution ( method ) to solve the problem ?
Any help would be much appreciated.
Array.prototype.reduce() can also be an option:
const arr =[
[{a: 1, b: 2},{a: 1, b: 3}],
[{a: 5, b: 2},{a: 2, b: 5}]
]
const expectedArray = arr.reduce((acc, array) => {
acc.push(...array);
return acc;
}, []);
You can use array.flat
let a = [
[{
a: 1,
b: 2
}, {
a: 1,
b: 3
}],
[{
a: 5,
b: 2
}, {
a: 2,
b: 5
}]
];
let b = a.flat();
console.log(b)
Alternatively you can use reduce and inside callback use forEach and puch items from the nested array to accumulator array
let a = [
[{
a: 1,
b: 2
}, {
a: 1,
b: 3
}],
[{
a: 5,
b: 2
}, {
a: 2,
b: 5
}]
];
let b = a.reduce((acc, curr) => {
curr.forEach(item => acc.push(item))
return acc;
}, []);
console.log(b)
use reduce() + push which faster flat() method.
refer this for to check performance. : https://jsbench.me/0ikcqa83ck/1
let arr = [
[{a: 1, b: 2},{a: 1, b: 3} ],
[{a: 5, b: 2},{a: 2, b: 5}]
]
console.log(arr.flat())
let flattenArr = arr.reduce((acc, val) => (acc.push(...val),acc), [])
console.log(flattenArr);
Array.flat is the magical solution you are looking for !
var arr = [
[{a: 1, b: 2},{a: 1, b: 3} ],
[{a: 5, b: 2},{a: 2, b: 5}]
]
console.log(arr.flat())

How to map more than one property from an array of objects [duplicate]

This question already has answers here:
Extract certain properties from all objects in array
(5 answers)
Closed 4 months ago.
I have an array of Object as follows:
var obj = [
{a: 1, b: 5, c: 9},
{a: 2, b: 6, c: 10},
{a: 3, b: 7, c: 11},
{a: 4, b: 8, c: 12}
];
I know about how to get single object using Array.map() like this.
var result = obj.map(x=>x.a)
This will give me following result
[1, 2, 3, 4]
But I want result like follows:
[
{a: 1, b: 5},
{a: 2, b: 6},
{a: 3, b: 7},
{a: 4, b: 8}
]
In short, from an array of objects I want to select only a few fields (more than one).
How can I do that?
You can use .map() with Object Destructuring:
let data = [
{a:1,b:5,c:9}, {a:2,b:6,c:10},
{a:3,b:7,c:11}, {a:4,b:8,c:12}
];
let result = data.map(({ a, b }) => ({a, b}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If, as in your example, you want to exclude a particular property or few, you can use destructuring and use rest properties to create an object with only the properties you want:
var obj = [
{a:1,b:5,c:9},
{a:2,b:6,c:10},
{a:3,b:7,c:11},
{a:4,b:8,c:12}
];
const mapped = obj.map(({ c, ...rest }) => rest);
console.log(mapped);
If you want to include properties, simply extract them from the .map callback:
var obj = [
{a:1,b:5,c:9},
{a:2,b:6,c:10},
{a:3,b:7,c:11},
{a:4,b:8,c:12}
];
const mapped = obj.map(({ a, b }) => ({ a, b }));
console.log(mapped);
Use map():
var data = [
{a:1,b:5,c:9},
{a:2,b:6,c:10},
{a:3,b:7,c:11},
{a:4,b:8,c:12}
];
let modified = data.map(obj => ({a: obj.a, b: obj.b}))
console.log(modified);
Or if you prefer destructuring:
var data = [
{a:1,b:5,c:9},
{a:2,b:6,c:10},
{a:3,b:7,c:11},
{a:4,b:8,c:12}
];
let modified = data.map(({ a, b }) => ({a, b}));
console.log(modified);
var obj = [
{a: 1, b: 5, c: 9},
{a: 2, b: 6, c: 10},
{a: 3, b: 7, c: 11},
{a: 4, b: 8, c: 12}
];
var result = obj.map(e => ({a:e.a , b:e.b}));
console.log(result)
You can return a custom object with required properties using map()
var obj = [{a:1,b:5,c:9},
{a:2,b:6,c:10},
{a:3,b:7,c:11},
{a:4,b:8,c:12}
];
let op = obj.map(e => {
return { a:e.a, b: e.b };
})
console.log(op);
In your solution for producing [1,2,3,4], x.a isn’t some micro-syntax, it’s actually a full-fledged JavaScript expression. So you can just replace it with the JavaScript for creating a new object with the properties you want.
var result = obj.map(x=>{a: x.a, b: x.b});
... almost. The additional complication is that a { after a => is interpreted as the beginning of a function body, not the beginning of an object literal. You can avoid this by just wrapping the object literal in otherwise-noop parenthesis.
var result = obj.map(x=>({a: x.a, b: x.b}));
You can make your own custom function for this, and pass it a set of properties which you want to extract. :
var array = [{a:1,b:5,c:9}, {a:2,b:6,c:10}, {a:3,b:7,c:11}, {a:4,b:8,c:12} ];
function extractProperties(arr, properties){
return arr.map((obj)=> Object.keys(obj).reduce((acc,key)=>{
if(properties.has(key))
acc[key] = obj[key];
return acc;
},{}));
}
let set = new Set(["a","b"]);
let result = extractProperties(array, set);
console.log(result);
set.add("c");
console.log("**************result2**********")
let result2 = extractProperties(array, set);
console.log(result2);

Return an Array of Arrays containing objects that share a common value in a property

Say I have an array of 3 objects like this:
[
{
a: 4,
b: 5,
c: 4
},
{
a: 3,
b: 5,
c: 6
},
{
a: 2,
b: 3,
c: 3
}
]
I would like to return an array of arrays containing the objects that share a common value for the property b. So the resulting array would contain only one array containing 2 objects like this:
[
[
{
a: 4,
b: 5,
c: 4
},
{
a: 3,
b: 5,
c: 6
}
]
]
How would I do this?
You could do this with map and filter
var data = [{"a":4,"b":5,"c":4},{"a":3,"b":5,"c":6},{"a":2,"b":3,"c":3}];
var check = data.map(e => {return e.b});
var result = [data.filter(e => { return check.indexOf(e.b) != check.lastIndexOf(e.b)})];
console.log(result)
To group multiple objects in separate arrays with same b values you can use map and forEach
var data = [{"a":4,"b":5,"c":4},{"a":3,"b":5,"c":6},{"a":2,"b":3,"c":3}, {"a":3,"b":7,"c":6},{"a":2,"b":7,"c":3}], result = [];
var check = data.map(e => {return e.b});
data.forEach(function(e) {
if(check.indexOf(e.b) != check.lastIndexOf(e.b) && !this[e.b]) {
this[e.b] = [];
result.push(this[e.b]);
}
(this[e.b] || []).push(e);
}, {});
console.log(result)
This proposal uses a single loop with Array#forEach but without Array#indexOf.
var array = [{ a: 4, b: 5, c: 4 }, { a: 3, b: 5, c: 6 }, { a: 2, b: 3, c: 3 }],
grouped = [];
array.forEach(function (a) {
this[a.b] = this[a.b] || [];
this[a.b].push(a);
this[a.b].length === 2 && grouped.push(this[a.b]);
}, Object.create(null));
console.log(grouped);
You can create a function that accepts fulfillment criteria and will return as many nested arrays as rules passed.
Let's say you have an array of objects, arr.
var arr = [{a: 1, b: 2}, {a: 3, b: 2}, {a: 3, b: 4}, {a: 1, b: 1}]
And you want to return an array with with nested arrays that fulfill a particular requirement, let's say you want objects with an a:1 and b:2.
You can create a function that loops through your rules and creates a nested array with the objects that fulfill each rule.
For example:
var arr = [{a: 1, b: 2}, {a: 3, b: 2}, {a: 3, b: 4}, {a: 1, b: 1}]
function makeNestedArrays() {
var rules = [].slice.call(arguments);
return rules.reduce(function(acc, fn) {
var nestedArr = [];
arr.forEach(function(obj) {
if (fn(obj)) {
nestedArr.push(obj);
}
});
// only push nested array
// if there are matches
if (nestedArr.length) {
acc.push(nestedArr);
}
return acc;
}, []);
}
var result = makeNestedArrays(
function(obj) { return obj.a === 1; },
function(obj) { return obj.b === 2; }
);
console.log(result);
This allows you to pass as many "rules" as you want, and will create a nested array for each rule so long as there is at least one match.
You could use a Map to group them, this should work with any kind of value (just be sure the equality rules check out):
var arr = [{
a: 4,
b: 5,
c: 4
}, {
a: 3,
b: 5,
c: 6
}, {
a: 2,
b: 3,
c: 3
}];
var result = arr.reduce(function(m, o){
var value = o.b;
if(m.has(value)){
m.get(value).push(o);
} else {
m.set(value, [o]);
}
return m;
}, new Map());
console.log(...(result.values()));
If you'd need to filter out the groups of 1:
var arr = [{
a: 4,
b: 5,
c: 4
}, {
a: 3,
b: 5,
c: 6
}, {
a: 2,
b: 3,
c: 3
}];
var result = arr.reduce(function(m, o){
var value = o.b;
if(m.has(value)){
m.get(value).push(o);
} else {
m.set(value, [o]);
}
return m;
}, new Map());
result = [...result.values()].filter(a => a.length > 1);
console.log(result);

Categories

Resources