Remove object items from array of objects and group in node js - javascript

I have an array of objects as an input.
var val = [{matnr :'0001',type:'Z0001',price:12.3,location:'Afr'},{matnr :'0001',type:'Z0002',price:12.2,location:'US'},
,{matnr :'0002',type:'Z0003',price:11.2,location:'EU'}]
I need to remove location from each object and group by material.
val = [{
matnr:0001
types :[{type:'Z001',price:12.3},{type:'Z001',price:12.2}]
},
{
matnr:0002
types :[{type:'Z003',price:12.3}]
}
I tried to delete an object from an array and did a group by but seems to be not working. Could you please help
val.forEach((values)=>
Object.keys(values).forEach(function (item) {
if (item !='matnr'||item !='type' || item != price){
delete values[item];
};
})
var grouped = _.groupBy(val, function(val) {
return val.matnr;
});

You can use .reduce() with destructuring to remove the location property and group attributes by matnr by creating an object, where each key is matnr, and each value is an accumulation of properties for that given matnr like so:
const arr = [{matnr:"0001",type:"Z0001",price:12.3,location:"Afr"},{matnr:"0001",type:"Z0002",price:12.2,location:"US"},{matnr:"0002",type:"Z0003",price:11.2,location:"EU"}];
const res = Object.values(arr.reduce((acc, {matnr, type, price}) => {
const {types = []} = acc[matnr] || {};
acc[matnr] = {matnr, types: [...types, {type, price}]};
return acc;
}, Object.create(null)));
console.log(res);
.as-console-wrapper {max-height: 100% !important;}

you can do this without using loadash simply by using the higher-order functions
const cleaned = removeFromList(list).key('location')
const grouped = group(list).by('matnr')
function removeFromList(arr) {
return {
key: key => arr.map(item => {
if (!item[key]) return item
delete item[key]
return item
})
}
}
function group(arr) {
return {
by: groupKey => {
const groupsObj = arr.reduce((groups, item) => {
const groupKeyValue = item[groupKey]
if(!groupKeyValue) return groups
if (!groups[groupKeyValue]){
groups[groupKeyValue] = [item]
return groups
}
groups[groupKeyValue] = [...groups[groupKeyValue], item]
return groups
}, {});
return groupsObj
}
}
}
Note We Prefer the object structures for performance and easy access as developers, so on the group by function we return the grouped object with the materials values as keys and the matches as their values.
Like :
{
0001 : [{type:'Z001',price:12.3},{type:'Z001',price:12.2}]
0002 : [{type:'Z003',price:12.3}]
}
example available here on repl.it

Related

new Array Conditional values

I need to create a new array as you can see it has a key value that specifies the latitude and longitude.
I want the key values ​​that are equal to be set as 1 only but according to who has the highest count
[
{
"color":"green",
"coment_calification":"Califica",
"count":7,
"key":"-13.0711552&-76.3723776&Califica",
"latitud":"-13.0711552",
"longitud":"-76.3723776"
},
{
"color":"yellow",
"coment_calification":"Reporte",
"count":6,
"key":"-13.0711552&-76.3723776&Reporte",
"latitud":"-13.0711552",
"longitud":"-76.3723776"
},
{
"color":"green",
"coment_calification":"Califica",
"count":1,
"key":"-13.1711552&-76.3423776&Califica",
"latitud":"-13.1711552",
"longitud":"-76.3423776"
},
{
"color":"yellow",
"coment_calification":"Reporte",
"count":2,
"key":"-13.1711552&-76.3423776&Reporte",
"latitud":"-13.1711552",
"longitud":"-76.3423776"
}
]
let result = count.filter((e) => e && e.count && e.key == e.key);
let datas = result;
Is this what you're looking for?
const result = arr.reduce((acc, cur) => {
const matchIndex = acc.findIndex(saved =>
saved.latitud === cur.latitud
&& saved.longitud === cur.longitud
);
if (matchIndex !== -1) {
if (cur.count > acc[matchIndex].count) {
acc.splice(matchIndex, 1, cur);
}
return acc;
}
return [...acc, cur];
}, []);
It looks like the array contains objects that differ mostly by their count props but have several other duplicate props. I think I understand the OP to want to remove these almost-duplicates retaining the one with the highest count.
One way to do this is to sort the array to be descending by count, walk through them, pushing onto a result only those that aren't already in the result.
The only thing not super clear in the OP is what constitutes sameness besides the count field. Here, we guess that the coment_calification key being the same means the objects are to be treated as duplicate.
const objects = [
{
"color":"green",
"coment_calification":"Califica",
"count":7,
"key":"-13.0711552&-76.3723776&Califica",
"latitud":"-13.0711552",
"longitud":"-76.3723776"
},
{
"color":"yellow",
"coment_calification":"Reporte",
"count":6,
"key":"-13.0711552&-76.3723776&Reporte",
"latitud":"-13.0711552",
"longitud":"-76.3723776"
},
{
"color":"green",
"coment_calification":"Califica",
"count":1,
"key":"-13.1711552&-76.3423776&Califica",
"latitud":"-13.1711552",
"longitud":"-76.3423776"
},
{
"color":"yellow",
"coment_calification":"Reporte",
"count":2,
"key":"-13.1711552&-76.3423776&Reporte",
"latitud":"-13.1711552",
"longitud":"-76.3423776"
}
];
objects.sort((a,b) => b.count-a.count) // sort descending
const result = [];
for (let object of objects) {
// supposing matching coment_calification props means a match
let alreadyInResult = result.find(r => r.coment_calification === object.coment_calification)
if (!alreadyInResult) result.push(object);
}
console.log(result)

From an array of data items how to group, create and collect other, key specific data?

I have an array of objects that looks like below
var FinalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"}];
I am trying to loop through the array and return an array of items group by the key "name" which will hold indexes of the items with same key.
expected result like below:
[
{bene: [0,2]},
{leg: [1,3]},
{hello: [4]}
]
I've put together the below but can't get it to work.
var obj = FinalArray.reduce(function(agg, item, index, f) {
var name = item.name || ""
var index = FinalArray.findIndex(item)
/* var copy = [...item.jArray];
*/ if (!agg[name]) {
agg[name] = []
}
agg[name].push(index)
return agg;
}, {})
fairly new to using reduce and groupby. any help is appreciated. Thanks
You can generate an object of the names with their indexes with a reduce on the original array, just pushing indexes into the array for each name.
If you then want an array of those values (I'm not sure this is a better structure), you can use Object.entries to get the key value pairs and map those into individual objects in an array
var FinalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"}];
var obj = FinalArray.reduce((acc, { name }, i) => {
acc[name] = (acc[name] || []).concat([i])
return acc
}, {})
console.log(obj)
objArray = Object.entries(obj).map(([k, v]) => ({ [k] : v }))
console.log(objArray)
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can achieve this by just using two JavaScript methods Array.forEach() along with Object.keys().
Live Demo :
// Input array
var FinalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"}
];
const resObj = {};
const output = [];
// creating a object with the required key: values.
FinalArray.forEach((obj, index) => {
resObj[obj.name] ? resObj[obj.name].push(index) : resObj[obj.name] = [index];
});
// destructuring the object into an array of objects.
Object.keys(resObj).forEach(key => {
output.push({
[key]: resObj[key]
})
});
// final output
console.log(output);
The OP might try a combination of ...
a reduce based approach which straightforwardly creates and collects an index/map of name based groups where the group key resemble an iterated item's name key, and the group value is an array of same name-value item-indices.
and a mapping of the reduced object's entries.
const finalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
];
console.log(
'index/map based result ...',
finalArray
.reduce((groups, { name }, idx) => {
(groups[name] ??= []).push(idx);
return groups;
}, {})
);
console.log(
"OP's expected result ...",
Object
.entries(
finalArray
.reduce((groups, { name }, idx) => {
(groups[name] ??= []).push(idx);
return groups;
}, {})
)
.map(([key, value]) => ({ [ key ]: value }))
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Another approach was to solely stick to reduce, where one then needs to implement a reducer function which achieves everything in a single run and does both ...
keeping track of the (to be) generated groups and the (to be) collected indices
and aggregating the final result of the reduce method's accumulator/collector object which gets passed as the method's 2nd parameter ... its initialValue.
const finalArray = [
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"123"},"name":"bene","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"B"}],"Ref":{"docId":"456"},"name":"leg","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
{"jArray":[{"Cd":"A"}],"Ref":{"docId":"789"},"name":"hello","check1":false,"check2":false,"check3":false,"check4":false,"id":"0001"},
];
const { result } = finalArray
.reduce(({ result = [], groups = {} }, { name }, idx) => {
let group = groups[name];
if (!group) {
group = groups[name] = { [ name ]: [] };
result.push(group);
}
group[name].push(idx)
return { result, groups };
}, { result: [] });
console.log({ result });
.as-console-wrapper { min-height: 100%!important; top: 0; }

How to fiter array with an array

I have a list of objects like this.
results = [
{ id: 1,
status : "Active"
// Some other fields
tags : [{val: 'IGM', color: 'light-success' },
{val: 'Gated Out', color: 'light-primary' },
]
},
// ...
]
now I want to filter objects in relation to tags,
the input to filter the list is also in the form of an array using multi-select input.
like
[{value: 'Gated Out', label: 'GATED OUT'}, .. ]
I'm able to filter data of other fields but not the tags because other fields are in strings and tags are an Array.
But now How can I modify this to work with the array as well.
I'm using that approach;
const handleTagsFilter = (value) => {
let updatedData = []
const dataToFilter = () => {
if (
status.length ||
custom_tags.length
) {
return filteredData
} else {
return results
}
}
setCustomTags(value)
if (value.length) {
updatedData = dataToFilter().filter((item) => {
const startsWith = item.status.toLowerCase().startsWith(value.toLowerCase())
const includes = item.status.toLowerCase().includes(value.toLowerCase())
if (startsWith) {
return startsWith
} else if (!startsWith && includes) {
return includes
} else return null
})
setFilteredData([...updatedData])
setCustomTags(value)
}
}
That function works with filtering strings like we have the status field to Active than this work, But I'm not sure how I can modify it to work with the array as well.
Maybe something like:
let search_str = 'abc'.toLowerCase();
let filtered_results = results
.map(v => v.tags.filter(_v => _v.val.toLowerCase().includes(search_str)))
.filter(v => v.length)
.reduce((a, b) => a.concat(...b), [])

How to update an object value in array of objects when the keys are same

I have an Array of objects and one object
const filterArray = [{bestTimeToVisit: 'Before 10am'}, {bestDayToVisit: Monday}]
This values are setting in a reducer and the payload will be like
{bestTimeToVisit: 'After 10am'}
or
{bestDayToVisit: Tuesday}.
So what I need is when I get a payload {bestTimeToVisit: 'After 10am'} and if bestTimeToVisit not in filterList array, then add this value to the filterList array.
And if bestTimeToVisit already in the array with different value, then replace the value of that object with same key
if(filterArray.hasOwnProperty("bestTimeToVisit")) {
filterArray["bestTimeToVisit"] = payload["bestTimeToVisit"];
} else {
filterArray.push({"bestTimeToVisit": payload["bestTimeToVisit"]});
}
I convert the object array into a regular object and then back into an object array. makes things less complicated. I'm making the assumption each object coming back only has one key/value and that order doesnt matter.
const objectArraytoObject = (arr) =>
arr.reduce((acc, item) => {
const key = [Object.keys(item)[0]];
return { ...acc, [key]: item[key] };
}, {});
const newValues = [{ someKey: 'something' }, { bestDayToVisit: 'Tuesday' }];
const filterArray = [
{ bestTimeToVisit: 'Before 10am' },
{ bestDayToVisit: 'Monday' },
];
const newValuesObj = objectArraytoObject(newValues);
const filterObj = objectArraytoObject(filterArray);
const combined = { ...filterObj, ...newValuesObj };
const combinedToArray = Object.keys(combined).map((key) => ({
[key]: combined[key],
}));
console.log(combinedToArray);
Need to iterate over the array and find objects that satisfy for modification or addition if none are found.
function checkReduced(filterrray,valueToCheck="After 10am"){
let isNotFound =true;
for(let timeItem of filterrray) {
if(timeItem.bestTimeToVisit && timeItem.bestTimeToVisit !== valueToCheck) {
timeItem.bestTimeToVisit=valueToCheck;
isNotFound=false;
break;
}
}
if(isNotFound){filterrray.push({bestTimeToVisit:valueToCheck})}
}
const filterArray = [{bestDayToVisit: "Monday"}];
checkReduced(filterArray,"After 9am");//calling the function
const updateOrAdd = (arr, newItem) => {
// get the new item key
const newItemKey = Object.keys(newItem)[0];
// get the object have the same key
const find = arr.find(item => Object.keys(item).includes(newItemKey));
if(find) { // the find object is a reference type
find[newItemKey] = newItem[newItemKey]; // update the value
} else {
arr.push(newItem); // push new item if there is no object have the same key
}
return arr;
}
// tests
updateOrAdd([{ a: 1 }], { b: 2 }) // => [{ a: 1 }, { b: 2 }]
updateOrAdd([{ a: 1 }], { a: 2 }) // => [{ a: 2 }]

How can I merge multiple arrays into multiple separate objects?

I have an object that has multiple arrays that looks something like this.
let obj = {
links: ["https://somelink.com/image.jpg", "https://somelink.com/image2.jpg"],
IDs: ["yCmj", "4q1K"],
}
I want to make it so that it's turned into an array of objects. Like the following.
let newObj = {
templates: [
{id:"yCmj", link: "https://somelink.com/image.jpg"},
{id:"4q1K", link: "https://somelink.com/image2.jpg"}
]
}
What I have tried:
I tried mapping the object values to a new array but the second map overwrites the whole array.
let templates = obj.templateIDs.map((id) => ({id}))
templates = obj.thumbnailLinks.map((thumbnailLink) => ({thumbnailLink}))
let newObj = templates
The easiest way to accomplish this would be to pick either obj.links or obj.IDs and map their values to an object and use the index to locate the corresponding parallel value.
const obj = {
links: ["https://somelink.com/image.jpg", "https://somelink.com/image2.jpg"],
IDs: ["yCmj", "4q1K"],
};
const newObj = {
templates: obj.links.map((link, index) => (id => ({ id, link }))(obj.IDs[index]))
};
console.log(newObj);
.as-console-wrapper { top: 0; max-height: 100% !important; }
This operation is typically called "zipping" 2 arrays:
const zip = (a,b, zipper) => {
if(a.length != b.length)
throw "arrays must be the same length";
return a.map( (v,i) => zipper(v,b[i]))
}
const obj = {
links: ["https://somelink.com/image.jpg", "https://somelink.com/image2.jpg"],
IDs: ["yCmj", "4q1K"],
}
const newObj = {
templates: zip(obj.links, obj.IDs, (link,id) => ({link,id}))
}
console.log(newObj);
You can simply use map.
const obj = {
links: ["https://somelink.com/image.jpg", "https://somelink.com/image2.jpg"],
IDs: ["yCmj", "4q1K"],
};
const newObj = {
templates: obj.links.map((link, i) => ({ link, id: obj.IDs[i] })),
};
console.log(newObj);
let obj = {
links: ["https://somelink.com/image.jpg", "https://somelink.com/image2.jpg","https://somelink.com/image2.jpg"],
IDs: ["yCmj", "4q1K","34er"],
}
let propsKey = Object.keys(obj)
let finalArr = obj.links.map( ()=> {
return {}
})
propsKey.forEach( (prop) => {
obj[prop].forEach( (v,i)=>finalArr[i][prop] = v )
})
console.log(finalArr)

Categories