This question already has answers here:
How can I group an array of objects by key?
(32 answers)
Closed 1 year ago.
The community reviewed whether to reopen this question 1 year ago and left it closed:
Original close reason(s) were not resolved
I am getting data like below :
data.filter = {
selectedFilterItems: [
{
name: "0-435",
categoryId: "0_435",
code: "price",
totalItems: 1,
},
{
name: "MULTI",
categoryId: "7608",
count: 633,
code: "color",
subcategories: [],
totalItems: 1,
},
{
name: "Pastel Tie Dye",
categoryId: "566962",
count: 1,
code: "color",
subcategories: [],
totalItems: 1,
},
],
totalItems: 3,
};
I need to create a json like below, where type will be the "code" i get from above data (i.e data.filter)
& the value will be comma seperated for common code.
Desired Output :
filters: [
{
type: 'price',
value: '0-435'
}
]
exg for color there will be only one type = color & its value will be "MULTI,Pastel Tie Dye".
if only one distinct code is there in data.filter then only that data will be in filters.
Here is the code which i am trying
if(data.filter) {
const selectedFilterItems = data.filter.selectedFilterItems.reduce((property, attribute) => {
if (property[attribute.code]) {
property[attribute.code].value += `,${attribute.name}`;
} else {
property[attribute.code] = { type: attribute.code, value: attribute.name };
}
return property;
}, {});
filter_data = Object.values(selectedFilterItems);
}
i need to add to the "filter_data" variable.
{
type: 'category',
value: '7608' // where the value will be there "selectedFilterItems's any of the property's categoryId's value.
}
You can use reduce() to filter the data and extract it with Object.values()
const data = { selectedFilterItems: [ { name: "0-435", categoryId: "0_435", code: "price", totalItems: 1, }, { name: "MULTI", categoryId: "7608", count: 633, code: "color", subcategories: [], totalItems: 1, }, { name: "Pastel Tie Dye", categoryId: "566962", count: 1, code: "color", subcategories: [], totalItems: 1, }, ], totalItems: 3, };
const groupByData = data.selectedFilterItems.reduce((acc, b) => {
if (acc[b.code]) {
acc[b.code].value += `,${b.name}`;
} else {
acc[b.code] = { type: b.code, value: b.name };
}
return acc;
}, {});
const output = Object.values(groupByData);
console.log(output);
let data = {};
data.filter = {
selectedFilterItems: [
{
name: "0-435",
categoryId: "0_435",
code: "price",
totalItems: 1,
},
{
name: "MULTI",
categoryId: "7608",
count: 633,
code: "color",
subcategories: [],
totalItems: 1,
},
{
name: "Pastel Tie Dye",
categoryId: "566962",
count: 1,
code: "color",
subcategories: [],
totalItems: 1,
},
],
totalItems: 3,
};
let filters = [];
let codes = []
data.filter.selectedFilterItems.forEach((elem)=>codes.push(elem.code)); //store all codes in an array
codes = [...new Set(codes)] //create a set of codes which will only contain unique entities
codes.forEach(code=>{ //Iterate over the codes
let obj = {}, val="";
data.filter.selectedFilterItems.forEach(elem=>{ //Iterate over each selectedFilterItems object
if(elem.code === code){
val += elem.name + ","; // Add the name to val if the code matches
}
})
val = val.substring(0, val.length-1); //Remove last char that will be comma
obj["type"] = code;
obj["value"] = val;
filters.push(obj)
})
console.log(filters)
Related
I have a question about how I can delete the existing elements, for example, in my case "Tallas" is repeated, could you please help me? Thank you very much to those who are willing to help me to solve this problem
const data =
[ { atributos: { Tallas: [{ id: 0, name: 'XS' }, { id: 1, name: 'S' }] }}
, { atributos: { Calzado: [{ id: 0, name: '10' }, { id: 1, name: '9.5' }] }}
, { atributos: { Tallas: [{ id: 0, name: 'XS' }] }}
]
The idea is to have this json format with the last "Tallas" since it is the last one that I added through my dynamic form.
const expected =
[{ atributos: { Calzado: [{ id: 0, name: '10' }, { id: 1, name: '9.5' }] }}
, { atributos: { Tallas: [{ id: 0, name: 'XS' }] }}
]
How do I do this is there a way to do it, I've tried with filter plus the findindex but I can't get to eliminate the repetition of the json res= new.filter((arr, index, self) => index === self.findIndex( (t) => (t.attributes === arr.attributes )))
To unique the array of objects, we can use the Javascript Set module, if the array has complex nested objects, we can stringify each object before creating new Set data. this below function will unique the array of complex objects.
function unique_array(array = []) {
const newSetData = new Set(array.map((e) => JSON.stringify(e)));
return Array.from(newSetData).map((e) => JSON.parse(e));
}
this is a function that takes an array and return the same array but delete every duplicated item
function removeDuplicates(arr) {
return arr.filter((item,
index) => arr.indexOf(item) === index);
}
I didn't understant the part written in spanish so I hope this is what you are looking for
This is a solution specific to your question. this is not a generic solution.
const data = [
{
atributos: {
Tallas: [
{ id: 0, name: "XS" },
{ id: 1, name: "S" },
],
},
},
{
atributos: {
Calzado: [
{ id: 0, name: "10" },
{ id: 1, name: "9.5" },
],
},
},
{
atributos: {
Tallas: [
{ id: 0, name: "XS" },
{ id: 1, name: "S" },
],
},
},
];
function uniqueArray(array) {
const resultObject = array.reduce((acc, eachValue) => {
let keys = Object.keys(eachValue.atributos);
keys.forEach((eachKey) => {
if (!acc[eachKey]) {
acc[eachKey] = [];
}
let list = eachValue["atributos"][eachKey].map(
(each) => each.id + "-" + each.name
);
acc[eachKey].push(...list);
});
return acc;
}, {});
const resultArray = Object.keys(resultObject).reduce((acc, each) => {
let setData = Array.from(new Set(resultObject[each]));
acc.push({
atributos: {
[each]: setData.map((e) => {
return { id: e.split("-")[0], name: e.split("-")[1] };
}),
},
});
return acc;
}, []);
return resultArray;
}
const result = uniqueArray(data)
console.log("result ", JSON.stringify(result, null, 2));
I am modifying an array of object using pure function but facing some challenge to modify userDetails object.
My requirement is instead 1, I need to show true inside permissions object. Please check my code and suggest. I know, I am doing some small mistake but still trying to identify.
I dont want main data source should get affected. Please suggest if you have any other good option
let data = [
{ id: 1,
title: 'admin1',
permissions: {
userDetails: { activeUser: 1, team: null},
salaryList: { abc: 1, def: 2, asdf: 0, poi: 1}
}
},
{ id: 1,
title: 'admin1',
permissions: {
userDetails: { activeUser: 1, team: null},
salaryList: { abc: 0, def: 1, asdf: null, poi: 0,wew: 1, aaa: 1}
}
},
]
let modifiedObjs = data.map( record => {
return {
id: record.id,
title: record.title + " Edited Object",
permissions: handlePermission(record.permissions)
}
})
function handlePermission(permissions){
Object.keys(permissions).forEach((key)=> {
Object.keys(permissions[key]).forEach((obj) => {
if(permissions[key][obj]===null){
delete permissions[key][obj]
}else{
const value = permissions[key][obj];
const finalV = value === 0? false : value ===1? true : value === 2 ? null : value;
permissions[key][obj] = finalV
}
})
})
return permissions
}
console.log(data, "main data")
console.log(modifiedObjs, "modified data")
The main issue with your code is that permissions is a reference inside of handlePermission, meaning that when you delete from it, it will also the key will also be removed from your original object (as they're sharing the same reference). One way to fix this is to instead build a new object. Whenever you find a key you want to keep, you can add it to the new object. Then, instead of deleting, you can simply not add the key/value to the object.
See example below:
const data = [{ id: 1, title: 'admin1', permissions: { userDetails: { activeUser: 1, team: null }, salaryList: { abc: 1, def: 2, asdf: 0, poi: 1 } } }, { id: 1, title: 'admin1', permissions: { userDetails: { activeUser: 1, team: null }, salaryList: { abc: 0, def: 1, asdf: null, poi: 0, wew: 1, aaa: 1 } } }, ];
let modifiedObjs = data.map( record => {
return {
id: record.id,
title: record.title + " Edited Object",
permissions: handlePermission(record.permissions)
}
});
function handlePermission(permissions){
const newPermissions = {};
Object.keys(permissions).forEach((key)=> {
newPermissions[key] = {}; // set object for key
Object.keys(permissions[key]).forEach((obj) => {
if(permissions[key][obj]!==null){
const value = permissions[key][obj];
const finalV = value === 0? false : value ===1? true : value === 2 ? null : value;
newPermissions[key][obj] = finalV;
}
});
});
return newPermissions;
}
console.log(data, "main data")
console.log(modifiedObjs, "modified data")
I would instead approach it like so, which uses Object.entries() to get a [key, value] pair array of entries from your object, along with Object.fromEntries() to reconstruct the object after its values have been mapped/filtered:
const data = [{ id: 1, title: 'admin1', permissions: { userDetails: { activeUser: 1, team: null }, salaryList: { abc: 1, def: 2, asdf: 0, poi: 1 } } }, { id: 1, title: 'admin1', permissions: { userDetails: { activeUser: 1, team: null }, salaryList: { abc: 0, def: 1, asdf: null, poi: 0, wew: 1, aaa: 1 } } }, ];
const modifiedObjs = data.map(({id, title, permissions}) => ({
id,
title: title + " Edited Object",
permissions: Object.fromEntries(Object.entries(permissions).map(([key, obj]) => [
key,
Object.fromEntries(Object.entries(obj).filter(([,v]) => v !== null)
.map(([k, v]) => [k, v > 1 ? null : !!v]))
]))
}));
console.log(data, "main data");
console.log(modifiedObjs, "modified data");
I would like to know how to change nested array object to object depending on key in javascript
I have objects obj1 and obj2, depending on key item type change the object.
function changeObj(obj){
let result = obj.reduce(function (acc, item) {
if(item.items.trim() !== "" && item.key.trim() !== ""){
acc[item.key] = item.items
return acc
}
return acc
}, {});
return result;
}
let result = this.changeObj(obj2)
var obj1 = [
{ id:0, items:["SG","AU"], count: 2, key:"countries"},
{ id:1, items:["finance"], count: 3 key:"info"}
]
var obj2 = [
{ id:0, items: "SG", key: "country"},
{ id:1, items: "details", key: "info"}
]
Expected Output:
// if items key is array
{
fields: {
countries: ["SG","AU",2],
info: ["finance",3]
}
}
//if items key is string
{
fields: {
country: "SG",
info: "details"
}
}
I think the reason your code is not running is because the wrong format of your objects (1 and 2). Your code is okay except the condition because trim() only works on string type so it errors on array. Try this code snippet
function changeObj(obj){
let result = obj.reduce(function (acc, item) {
acc[item.key] = item.items;
return acc;
}, {});
return result;
}
var obj1 = [
{ id:0, items:["SG","AU"], count: 2, key:"countries"},
{ id:1, items:["finance"], count: 3, key:"info"}
]
var obj2 = [
{ id:0, items: "SG", key: "country"},
{ id:1, items: "details", key: "info"}
]
console.log(changeObj(obj1));
const changeObj = obj =>
obj.reduce((acc, item) => {
if (Array.isArray(item.items)) {
acc[item.key] = [...item.items, item.count];
} else {
acc[item.key] = item.items;
}
return acc;
}, {});
var obj1 = [
{ id: 0, items: ['SG', 'AU'], count: 2, key: 'countries' },
{ id: 1, items: ['finance'], count: 3, key: 'info' }
];
var obj2 = [
{ id: 0, items: 'SG', key: 'country' },
{ id: 1, items: 'details', key: 'info' }
];
console.log(changeObj(obj1));
console.log(changeObj(obj2));
or cleaned up even more
const changeObj = obj =>
obj.reduce((acc, { items, key, count }) => {
Array.isArray(items) ? (acc[key] = [...items, count]) : (acc[key] = items);
return acc;
}, {});
var obj1 = [
{ id: 0, items: ['SG', 'AU'], count: 2, key: 'countries' },
{ id: 1, items: ['finance'], count: 3, key: 'info' }
];
var obj2 = [
{ id: 0, items: 'SG', key: 'country' },
{ id: 1, items: 'details', key: 'info' }
];
console.log(changeObj(obj1));
console.log(changeObj(obj2));
I have checked other solutions but none fit the criterion of my problem
This solution does not have the ability to dynamically check each node
Problem summarized
I wish to create an algorithm that is able to check an object that has nodes of different data types, for duplicated objects in nodes that are specifically of the datatype array.
I have the following dataset:
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 2 }, { id: 3 }],
};
I wish to be able to dynamically check which of the objects (or nodes? and the algo has to recognize that it is an array) has duplicates, and reduce them to be in this form:
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 3 }],
};
EDIT
The algorithm needs to be able to handle a dynamic number of nodes (example 1), however , the duplicates will only happen 1 level down (Thanks for pointing out).
example 1 (there is 1 less node here ) :
task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 2 }],
};
Here is my proposed solution to remove duplicate elements from any array in the task object:
const uniq = array => {
const map = {};
const result = [];
for (let i = 0; i < array.length; i++) {
// since elements can be objects, need to do a deep comparison.
const element = JSON.stringify(array[i]);
if (map[element] === undefined) {
map[element] = true;
result.push(array[i]);
}
}
return result;
}
const task = {
content: "lorem....",
customer: [
{ id: 1, name: "hello" },
{ id: 2, name: "sup" },
],
end: "2020-08-13 10:09:48",
project: [{ id: 1 }, { id: 1 }, { id: 2 }],
vendor: [{ id: 2 }, { id: 2 }, { id: 3 }],
};
for (const key in task) {
if (Array.isArray(task[key])) {
task[key] = uniq(task[key])
}
}
console.log('deduped:', task);
I have nested tree object I would like filter through without losing structure
var items = [
{
name: "a1",
id: 1,
children: [{
name: "a2",
id: 2,
children: [{
name: "a3",
id: 3
}]
}]
}
];
so for example if id == 2 remove object with id 2 and his children
if id == 3 only remove object with id 3
this's just apiece of object to make question clean but the object it self contains more and more :)
using vanilla javascript, _lodash or Angular2 it's okay
thank you
You can create recursive function using filter() and also continue filtering children if value is Array.
var items = [{
name: "a1",
id: 1,
children: [{
name: "a2",
id: 2,
children: [{
name: "a3",
id: 3
}, ]
}]
}];
function filterData(data, id) {
var r = data.filter(function(o) {
Object.keys(o).forEach(function(e) {
if (Array.isArray(o[e])) o[e] = filterData(o[e], id);
})
return o.id != id
})
return r;
}
console.log(filterData(items, 3))
console.log(filterData(items, 2))
Update: As Nina said if you know that children is property with array you don't need to loop keys you can directly target children property.
var items = [{
name: "a1",
id: 1,
children: [{
name: "a2",
id: 2,
children: [{
name: "a3",
id: 3
}, ]
}]
}];
const filterData = (data, id) => data.filter(o => {
if (o.children) o.children = filterData(o.children, id);
return o.id != id
})
console.log(JSON.stringify(filterData(items, 3), 0, 2))
console.log(JSON.stringify(filterData(items, 2), 0, 2))
If it's ok for your case to use Lodash+Deepdash, then:
let filtered = _.filterDeep(items,(i)=>i.id!=3,{tree:true});
Here is a demo Codepen
You could use an iterative approach with Array#some and call the callback iter recursive for the children. I found, splice.
function deleteItem(id) {
items.some(function iter(a, i, aa) {
if (a.id === id) {
aa.splice(i, 1);
return true;
}
return a.children.some(iter);
});
}
var items = [{ name: "a1", id: 1, children: [{ name: "a2", id: 2, children: [{ name: "a3", id: 3 }] }] }];
console.log(items);
deleteItem(3);
console.log(items);
deleteItem(2);
console.log(items);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Use recursive function:
var items = [
{
name: "a1",
id: 1,
children: [{
name: "a2",
id: 2,
children: [{
name: "a3",
id: 3,
children: [{
name: "a4",
id: 4,
}]
}]
}]
}
];
function filterId(items, id) {
var len = items.length;
while (len--) {
if (items[len].id === id) {
items.splice(len, 1);
break;
} else {
filterId(items[len].children, id);
}
}
return items;
}
// filtering out the item with 'id' = 4
console.log(filterId(items, 4));
// filtering out the item with 'id' = 2
console.log(filterId(items, 2));