JavaScript divide array of objects by field - javascript

I have a JSON file like this:
[
{
"type": -1,
"name": "First Group"
},
{
"type": 2,
"name": "A"
},
{
"type": 3,
"name": "B"
},
{
"type": 4,
"name": "C"
},
{
"type": -1,
"name": "Second Group"
},
{
"type": 3,
"name": "B"
},
{
"type": 4,
"name": "C"
},
{
"type": -1,
"name": "Third Group"
},
{
"type": 4,
"name": "C"
},
{
"type": 2,
"name": "A"
}
]
And I would like to divide this array of objects on many arrays, and grouping it by "type": -1 field.
For example for current JSON I would like to get something like this:
1)
[
{
"type": -1,
"name": "First Group"
},
{
"type": 2,
"name": "A"
},
{
"type": 3,
"name": "B"
},
{
"type": 4,
"name": "C"
}
]
2)
[
{
"type": -1,
"name": "Second Group"
},
{
"type": 3,
"name": "B"
},
{
"type": 4,
"name": "C"
}
]
3)
[
{
"type": -1,
"name": "Third Group"
},
{
"type": 4,
"name": "C"
},
{
"type": 2,
"name": "A"
}
]
My question in the next:
Does it exist some function on TypeScript/JavaScript for doing this? Or need to create something specific. And if doesn't exist then how to create a better and fast solution for this?

const arr = [{"type": -1,"name": "First Group"},{"type": 2,"name": "A"},{"type": 3,"name": "B"},{"type": 4,"name": "C"},{"type": -1,"name": "Second Group"},{"type": 3,"name": "B"},{"type": 4,"name": "C"},{"type": -1,"name": "Third Group"},{"type": 4,"name": "C"},{"type": 2,"name": "A"}];
const chunks = [];
let chunk = [];
arr.forEach((item) => {
if(item.type === -1) {
if(chunk.length) {
chunks.push(chunk);
}
chunk = [];
}
chunk.push(item);
});
chunks.push(chunk);
console.log(chunks);

Just try following simple logic.
var data = [
{
"type": -1,
"name": "First Group"
},
{
"type": 2,
"name": "A"
},
{
"type": 3,
"name": "B"
},
{
"type": 4,
"name": "C"
},
{
"type": -1,
"name": "Second Group"
},
{
"type": 3,
"name": "B"
},
{
"type": 4,
"name": "C"
},
{
"type": -1,
"name": "Third Group"
},
{
"type": 4,
"name": "C"
},
{
"type": 2,
"name": "A"
}
];
var output = [],
_index = 0;
data.forEach(function(obj){
if(obj.type == -1){
output.push([obj]);
_index++;
} else {
output[_index-1].push(obj);
}
});
console.log(output);

Use Array.prototype.reduce:
const collection = [{
"type": -1,
"name": "First Group"
},
{
"type": 2,
"name": "A"
},
{
"type": 3,
"name": "B"
},
{
"type": 4,
"name": "C"
},
{
"type": -1,
"name": "Second Group"
},
{
"type": 3,
"name": "B"
},
{
"type": 4,
"name": "C"
},
{
"type": -1,
"name": "Third Group"
},
{
"type": 4,
"name": "C"
},
{
"type": 2,
"name": "A"
}
]
const makeReducerByTypeValue = value => (result, el, index) => {
if (el.type === value) {
result.sorted.push([])
if (index > 0) result.currentIndex++
}
result.sorted[result.currentIndex].push(el)
return result
}
const sorted = collection.reduce(makeReducerByTypeValue(-1), {
currentIndex: 0,
sorted: []
}).sorted
sorted.forEach(el => console.log(el))

There is no built-in function or method for this to get the wanted groups.
You could take a new array for every found type equals -1 and take for all other types the last inserted array of the result set.
This works obviously only for sorted arrays only.
var array = [{ type: -1, name: "First Group" }, { type: 2, name: "A" }, { type: 3, name: "B" }, { type: 4, name: "C" }, { type: -1, name: "Second Group" }, { type: 3, name: "B" }, { type: 4, name: "C" }, { type: -1, name: "Third Group" }, { type: 4, name: "C" }, { type: 2, name: "A" }],
grouped = array.reduce(function (r, a) {
if (a.type === -1) {
r.push([a]);
} else {
r[r.length - 1].push(a);
}
return r;
}, []);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Find user details by ID in nested object nodejs | javascript

How to find name using id. means iterate object. create a function const searchName =()=>{}
suppose if pass 3 in function so I'd want to show .... what the name of user like this
const data = [{
"service": [
"BUSINESS",
"LEGAL",
"FINANCE",
"ADVERTISEMENT"
],
"service1": [
{ "id": 1, "name": "a" },
{ "id": 2, "name": "b" },
{ "id": 3, "name": "c" },
{ "id": 4, "name": "d" },
],
"service2": [
{ "id": 5, "name": "e" },
{ "id": 6, "name": "f" },
{ "id": 7, "name": "g" },
{ "id": 8, "name": "h" },
],
"service3": [
{ "id": 9, "name": "i" },
{ "id": 10, "name": "j" },
{ "id": 11, "name": "k" },
{ "id": 12, "name": "l" },
],
"service4": [
{ "id": 13, "name": "m" },
{ "id": 14, "name": "n" },
{ "id": 15, "name": "o" },
{ "id": 16, "name": "p" },
],
}
]
suppose user pass 3 so I want to return { "id": 3, "name": "c" } like this.
I'm trying to iterate this and find the name of the user by id but I didn't understand this iteration so I need your help.
check this code.... Enter any id number
const data = [{
"service": [
"BUSINESS",
"LEGAL",
"FINANCE",
"ADVERTISEMENT"
],
"service1": [
{ "id": 1, "name": "a" },
{ "id": 2, "name": "b" },
{ "id": 3, "name": "c" },
{ "id": 4, "name": "d" },
],
"service2": [
{ "id": 5, "name": "e" },
{ "id": 6, "name": "f" },
{ "id": 7, "name": "g" },
{ "id": 8, "name": "h" },
],
"service3": [
{ "id": 9, "name": "i" },
{ "id": 10, "name": "j" },
{ "id": 11, "name": "k" },
{ "id": 12, "name": "l" },
],
"service4": [
{ "id": 13, "name": "m" },
{ "id": 14, "name": "n" },
{ "id": 15, "name": "o" },
{ "id": 16, "name": "p" },
],
}]
var itemobj = ''
const searchName =(val)=>{
console.log('searchname')
data.map((item)=>{
let obj = Object.keys(item)
obj.map((data)=>{
let inrdata = item[data]
inrdata.map((initem)=>{
let lastdata = initem.id===val?itemobj=initem:null
})
})
})
}
searchName(3)
console.log(itemobj)
function searchName(id) {
let result = null;
for (const [key, value] of Object.entries(data)) {
if (key === "service") continue
result = value.filter(obj => {
return obj.id === id
})
if (result) break
}
return result ? result[0] : null
}
I iterate through keys, I just skip "service" one since it's not revelant.
Then, I filter the "serviceN" array, it will return an array of object (only one if found, empty array if not found).
If it's found, we stop iterating.
Then we return either the first (and logically only element) or null if not found
You could use a combination of flat and find to get get the user by id
function searchName(id) {
return data
.flatMap((item) => Object.values(item))
.flat()
.find((user) => user.id === id);
}
const result = searchName(3); // { id: 3, name: 'c' } | undefined

Reduce it array to an easier way to map

I'm developing an application and have added new items to my array: type and description.
array = [
{
"id": 1,
"description": "item1",
"date": {
"id": 1,
"name": "202001"
},
"item": {
"id": 1,
"name": "I1"
},
"type": {
"id": 1,
"name": "type1"
},
"price": 100
},
{
"id": 2,
"description": "item1",
"date": {
"id": 2,
"name": "202002"
},
"item": {
"id": 1,
"name": "I1"
},
"type": {
"id": 1,
"name": "type1"
},
"price": 200
},
{
"id": 3,
"description": "item1",
"date": {
"id": 2,
"name": "202002"
},
"item": {
"id": 2,
"name": "I2"
},
"type": {
"id": 2,
"name": "type2"
},
"price": 300
},
]
I previously did this to reduce it down to an easier way to map it:
items = array.reduce((acc, e) => {
if (!acc[e["item"]["name"]]) {
acc[e["item"]["name"]] = {
[e["date"]["name"]]: e["price"]
}
} else {
acc[e["item"]["name"]][e["date"]["name"]] = e["price"]
}
return acc
}, {})
To show the data before I did
const dates = [...new Set(Object.keys(items_dicc).map(i => Object.keys(items_dicc[i])).flat())]
{
Object.keys(items_dicc).map((item) => {
return (
<tr>
<td>{item}</td>
{dates.map((date) => <td>{items_dicc[item][date] || ''}</td>)}
</tr>
)
})
}
I need to add the description element and type.name to the above. For example for description:
description: e["description"]
To display the elements as in the table:
ITEM
DESCRIPTION
TYPE
202001
202002
I1
item1
type1
100
200
I2
item3
type2
-
300
How do I add and show?
EDIT: console.log(items_dicc[item])
{202001: 100, 202002: 200, description: "item1", type: "type1"}
202001: 100
202002: 200
description: "item1"
type: "type1"
__proto__: Object
{202002: 300, description: "item3", type: "type2"}
202002: 300
description: "item3"
type: "type2"
__proto__: Object
You can add the description and type attribute inside the reduce method like this,
array = [
{
"id": 1,
"description": "item1",
"date": {
"id": 1,
"name": "202001"
},
"item": {
"id": 1,
"name": "I1"
},
"type": {
"id": 1,
"name": "type1"
},
"price": 100
},
{
"id": 2,
"description": "item2",
"date": {
"id": 2,
"name": "202002"
},
"item": {
"id": 1,
"name": "I1"
},
"type": {
"id": 1,
"name": "type1"
},
"price": 200
},
{
"id": 3,
"description": "item3",
"date": {
"id": 2,
"name": "202002"
},
"item": {
"id": 2,
"name": "I2"
},
"type": {
"id": 2,
"name": "type2"
},
"price": 300
},
]
items = array.reduce((acc, e) => {
if (!acc[e["item"]["name"]]) {
acc[e["item"]["name"]] = {
[e["date"]["name"]]: e["price"],
'description': e['description'],
'type': e.type?.name,
}
} else {
acc[e["item"]["name"]][e["date"]["name"]] = e["price"]
}
return acc
}, {})
console.log(items);
To add the for description and name in the table,
const dates = [...new Set(Object.keys(items_dicc).map(i => Object.keys(items_dicc[i])).flat())]
{
Object.keys(items_dicc).map((item) => {
return (
<tr>
<td>{item}</td>
<td>{items_dicc[item]?.description}</td>
<td>{items_dicc[item]?.type}</td>
{dates.map((date) => <td>{items_dicc[item][date] || ''}</td>)}
</tr>
)
})
}
I have been seeing your question regarding these type of tables from yesterday. You have posted several questions with similar things. I suggest you to read some article and understand how JS array methods works instead of asking incremental questions in SO.
Asking in SO might solve your problems for now, but in the long run you will suffer as you don't seem to have a grip on how these things works.
you can simplify your solution like this.
const array = [{
"id": 1,
"description": "item1",
"date": {
"id": 1,
"name": "202001"
},
"item": {
"id": 1,
"name": "I1"
},
"type": {
"id": 1,
"name": "type1"
},
"price": 100
},
{
"id": 2,
"description": "item2",
"date": {
"id": 2,
"name": "202002"
},
"item": {
"id": 1,
"name": "I1"
},
"type": {
"id": 1,
"name": "type1"
},
"price": 200
},
{
"id": 3,
"description": "item3",
"date": {
"id": 2,
"name": "202002"
},
"item": {
"id": 2,
"name": "I2"
},
"type": {
"id": 2,
"name": "type2"
},
"price": 300
}
]
const result = array.map(item => {
return Object.keys(item).reduce((a, c) => {
if (c === "date") {
a[item[c].name] = item.price;
} else if (c !== "price" && c !== "id") {
a[c] = (typeof item[c] === "object") ? item[c].name : item[c];
}
return a;
}, {})
});
console.log(result);

Using undescore.js, i'm trying to format the given input to an expected output

Input:
[{
"dimensions": [{
"name": "Size",
"value": "Size1"
},
{
"name": "Color",
"value": "Color1"
},
{
"name": "Pattern",
"value": "1"
}
],
"link": "link",
"title": "title"
},
{
"dimensions": [{
"name": "Size",
"value": "Size2"
},
{
"name": "Color",
"value": "Color1"
},
{
"name": "Pattern",
"value": "2"
}
],
"link": "link1",
"title": "title"
},
{
"dimensions": [{
"name": "Size",
"value": "Size1"
},
{
"name": "Color",
"value": "Color2"
},
{
"name": "Pattern",
"value": "1"
}
],
"link": "link",
"title": "title"
},
{
"dimensions": [{
"name": "Size",
"value": "Size2"
},
{
"name": "Color",
"value": "Color1"
},
{
"name": "Pattern",
"value": "3"
}
],
"link": "link",
"title": "title"
}]
Expected Output:
{
"levels":3,
"level_1_name":"Size",
"level_2_name":"Color",
"level_3_name":"Pattern",
"data":[
{
"value":"Size1",
"data":[
{
"value":"Color1",
"data":[
{
"value":"1"
}
]
}, {
"value":"Color2",
"data":[
{
"value":"4"
}
]
}
]
}, {
"value":"Size2",
"data":[
{
"value":"Color1",
"data":[
{
"value":"3"
}
]
},
{
"value":"Color2",
"data":[
{
"value":"2"
}
]
}
]
}
]
}
I've tried something like that
for(index=0; index<data[0].dimensions.length - 1; index++) {
let temp = _(data).groupBy(function(o) {
return o.dimensions[index].value
})
let keys = Object.keys(temp)
addData(final, keys, temp)
}
obj["data"] = final
function addData(data, keys, temp) {
if (data && data.length) {
return data.forEach(function(data1){
console.log(data1)
return addData(data1, keys, temp)
})
} else {
let data_arr = []
if (Array.isArray(data)) {
keys.forEach(function(key) {
data.push({
value: key,
data: temp[key]
})
})
} else {
keys.forEach(function(key) {
let data_obj = {}
data_obj['value'] = key
data_obj['data'] = temp[key]
data_arr.push(data_obj)
})
data["data"] = data_arr
}
}
}
I've tried the logic to format as per the expected output. It works with level 2 input set, But the logic written doesn't work for level 3 input data set.
Also It would be helpful if you can suggest any algorithms to sort this problem out.
Thanks in advance!
Here is a fairly compact solution using reduce(). (I've edited the input to match your expected output.)
const source = [{
"dimensions": [{
"name": "Size",
"value": "Size1"
},
{
"name": "Color",
"value": "Color1"
},
{
"name": "Pattern",
"value": "1"
}
],
"link": "link",
"title": "title"
},
{
"dimensions": [{
"name": "Size",
"value": "Size2"
},
{
"name": "Color",
"value": "Color2"
},
{
"name": "Pattern",
"value": "2"
}
],
"link": "link1",
"title": "title"
},
{
"dimensions": [{
"name": "Size",
"value": "Size1"
},
{
"name": "Color",
"value": "Color2"
},
{
"name": "Pattern",
"value": "4"
}
],
"link": "link",
"title": "title"
},
{
"dimensions": [{
"name": "Size",
"value": "Size2"
},
{
"name": "Color",
"value": "Color1"
},
{
"name": "Pattern",
"value": "3"
}
],
"link": "link",
"title": "title"
}];
const output = source.reduce((acc, {dimensions: dims}) => {
const levels = dims.length;
// initialize top-level keys based on first object
if (!acc.hasOwnProperty('levels')) {
acc.levels = levels;
dims.forEach((level, i) => acc[`level_${i+1}_name`] = level.name);
acc.data = [];
}
// iterate over dimension objects and merge with accumulator
let parent = acc.data;
dims.forEach((o, i) => {
let lvlObj = parent.find(e => e.value === o.value);
if (!lvlObj) {
lvlObj = i < levels - 1 ?
{value: o.value, data: []} :
{value: o.value};
parent.push({...lvlObj});
}
parent = lvlObj.data;
});
return acc;
}, {});
console.log(output);

Group elements of array by sub string JavaScript

I have a list of elements like this
[{
"id": 1,
"id_team": "1.",
"name": "Name",
}, {
"id": 2,
"id_team": "2.",
"name": "Name",
}, {
"id": 3,
"id_team": "3.",
"name": "Name",
}, {
"id": 4,
"id_team": "4.",
"name": "Name",
}, {
"id": 5,
"id_team": "5.",
"name": "Name",
}, {
"id": 6,
"id_team": "2.1.",
"name": "Name",
}, {
"id": 7,
"id_team": "6.",
"name": "Name",
}, {
"id": 8,
"id_team": "1.1.",
"name": "Name",
}, {
"id": 9,
"id_team": "1.2.",
"name": "Name",
}, {
"id": 10,
"id_team": "1.3.",
"name": "Name",
}, {
"id": 11,
"id_team": "1.4.",
"name": "Name",
}]
a shown in the example, i have some string in the column id_team that are inside other string in the same column in the array
For example, the main team would be 1. then 1.1. and 1.2. and so on would be part of 1.
so the result must be like this
[{
"id": 1,
"id_team": "1.",
"name": "Name",
"subteams": [{
"id": 8,
"id_team": "1.1.",
"name": "Name",
}, {
"id": 9,
"id_team": "1.2.",
"name": "Name",
}, {
"id": 10,
"id_team": "1.3.",
"name": "Name",
}, {
"id": 11,
"id_team": "1.4.",
"name": "Name",
},],
}, {
"id": 2,
"id_team": "2.",
"name": "Name",
"subitems": [{
"id": 6,
"id_team": "2.1.",
"name": "Name",
},]
}, {
"id": 3,
"id_team": "3.",
"name": "Name",
"subitems": [],
}, {
"id": 4,
"id_team": "4.",
"name": "Name",
"subitems": [],
}, {
"id": 5,
"id_team": "5.",
"name": "Name",
"subitems": [],
}, {
"id": 7,
"id_team": "6.",
"name": "Name",
"subitems": [],
},]
it is doable? i use lodash if it would make it easier.
EDIT
I have something like this
teams.filter(item => item.id_team.length <= size).map((item) => {
const subteams = teams.filter((team) =>
team.id_team.indexOf(item.id_team) === 0 && item.id_team !== team.id_team);
console.log(subteams);
return {
...item,
subteams,
};
}) || [];
this kinda work, as it will insert in the sub teams array, but the problem is that this must work for many levels, take this example
[{
"id": 1,
"id_team": "1.",
"name": "Team Name",
"subteams": [{
"id": 8,
"id_team": "1.1.",
"name": "Team Name",
}, {
"id": 9,
"id_team": "1.2.",
"name": "Team Name",
}, {
"id": 10,
"id_team": "1.3.",
"name": "Team Name",
}, {
"id": 11,
"id_team": "1.4.",
"name": "Team Name",
}, {
"id": 12,
"id_team": "1.1.1",
"name": "Team Name",
}]
}, {
"id": 2,
"id_team": "2.",
"name": "Team Name",
"subteams": [{
"id": 6,
"id_team": "2.1.",
"name": "Team Name",
}]
}, {
"id": 3,
"id_team": "3.",
"name": "Team Name",
"subteams": []
}, {
"id": 4,
"id_team": "4.",
"name": "Team Name",
"subteams": []
}, {
"id": 5,
"id_team": "5.",
"name": "Team Name",
"subteams": []
}, {
"id": 7,
"id_team": "6.",
"name": "Team Name",
"subteams": []
}]
in this example there is a team with id_team = 1.1.1., how can i add that team to a sub team of the team with id_team 1.1. with the same logic, i tried to use the same code recursively but it didnt work.
const items = data.reduce((acc, item, index) => {
const id_team = item.id_team.split('.')[0] + '.';
const current = acc.find(record => record.id_team === id_team);
if(current) current.subteams.push(item);
else acc.push({
id: index + 1,
id_team,
subteams: [item]
});
return acc;
}, []);
let data = [{
"id": 1,
"id_team": "1.",
"name": "Name",
}, {
"id": 2,
"id_team": "2.",
"name": "Name",
}, {
"id": 3,
"id_team": "3.",
"name": "Name",
}, {
"id": 4,
"id_team": "4.",
"name": "Name",
}, {
"id": 5,
"id_team": "1.2.5.",
"name": "Name",
}, {
"id": 6,
"id_team": "2.1.",
"name": "Name",
}, {
"id": 7,
"id_team": "6.",
"name": "Name",
}, {
"id": 8,
"id_team": "1.1.",
"name": "Name",
}, {
"id": 9,
"id_team": "1.2.",
"name": "Name",
}, {
"id": 10,
"id_team": "1.3.",
"name": "Name",
}, {
"id": 11,
"id_team": "1.4.",
"name": "Name",
}];
data = data.map(node=>{
let t = node.id_team.split('.').filter(n=>n);
let parent = t.splice(0,t.length-1).join('.');
return {
...node,
parent: !!parent ? parent+'.' : null
}
});
let tree = (items, id = null) =>
items
.filter(item => item.parent === id)
.map(item => ({ ...item, subTeams: tree(items, item.id_team) }));
console.log(JSON.stringify(tree(data),null,2));
From the code of the example, i just checked if the subteams array has data, if it does, i use an auxiliar with the recursive function and assigned it to the subteams.
getSubTeams(teams, size) {
const filtered = teams.filter(item => item.id_team.length <= size);
return filtered.map((item) => {
let subteams = teams.filter((team) => team.id_team.indexOf(item.id_team) === 0 && item.id_team !== team.id_team);
if (subteams.length > 0) {
let aux = this.getSubTeams(subteams, size + 2);
subteams = [
...aux,
];
}
return {
...item,
subteams,
};
}) || [];
},

angularjs md checkbox get the checked values

<md-checkbox ng-repeat="primaryPrograms in ctrl.primaryProgramStudies" ng-model="ctrl.primaryProgramStudiesSelected[primaryPrograms.id]">
{{primaryPrograms.name}}
</md-checkbox>
Selected Checbox :
{{ctrl.primaryProgramStudiesSelected | json}}
Output i am getting :
Selected Checbox :
[null,true,true,true,null,true,null,true,null,true,null,null,true]
How can i get the List of Checked Values.
You can filter the original array ctrl.primaryProgramStudies based on whether the same index on ctrl.primaryProgramStudiesSelected has true
var ctrl = {};
ctrl.primaryProgramStudies = [{
"name": "test0",
"id": 0
},
{
"name": "test1",
"id": 1
},
{
"name": "test2",
"id": 2
},
{
"name": "test3",
"id": 3
},
{
"name": "test4",
"id": 4
},
{
"name": "test5",
"id": 5
},
{
"name": "test6",
"id": 6
},
{
"name": "test7",
"id": 7
},
{
"name": "test8",
"id": 8
},
{
"name": "test9",
"id": 9
},
{
"name": "test10",
"id": 10
},
{
"name": "test11",
"id": 11
},
{
"name": "test12",
"id": 12
}
]
ctrl.primaryProgramStudiesSelected = [null, true, true, true, null, true, null, true, null, true, null, null, true]
ctrl.selectedValues = ctrl.primaryProgramStudies.filter(function(obj, index) {
return ctrl.primaryProgramStudiesSelected[index] === true
})
console.log(ctrl.selectedValues)
You can use filter method, which accepts as a parameter a callback method.
The filter() method creates a new array with all elements that pass the test implemented by the provided(callback) function.
var array=[null,true,true,true,null,true,null,true,null,true,null,null,true];
ctrl.primaryProgramStudies.filter(function(item,index){
return array[index]==true;
});
Short example
var ctrl = {};
ctrl.primaryProgramStudies = [{
"name": "program0"
},
{
"name": "program1"
},
{
"name": "program2"
},
{
"name": "program3"
},
{
"name": "program4"
},
{
"name": "program5"
},
{
"name": "program6"
},
{
"name": "program7"
},
{
"name": "program8",
},
{
"name": "program9",
},
{
"name": "program10",
},
{
"name": "program11",
},
{
"name": "program12"
}
]
ctrl.primaryProgramStudiesSelected =[null,true,true,true,null,true,null,true,null,true,null,null,true];
var result=ctrl.primaryProgramStudies.filter(function(item,index){
return ctrl.primaryProgramStudiesSelected[index]==true;
});
console.log(result)

Categories