Reputation: 747
Essentially, I' trying to end up with an array that looks like this:
{
"projects" : [{
"project" : "Project One",
"tasks" : [{
"name" : "Task One"
}, {
"name" : "Task Two"
}, {
"name" : "Task Three"
}]
}, {
"project" : "Project Two",
"tasks" : [{
"name" : "Task One"
}, {
"name" : "Task Two"
}]
}]
}
I currently have the following array and a script which look at each element of tasks and checks to see that it's not already in a list of project names, then inserts the first one if it's not, and should add a second element if it is, but that's where I'm a little stuck:
var tasks = [{
"name" : "Task One",
"project" : "Project One"
}, {
"name" : "Task One",
"project" : "Project Two"
}, {
"name" : "Task Two",
"project" : "Project One"
}, {
"name" : "Task Three",
"project" : "Project One"
}, {
"name" : "Task Two",
"project" : "Project Two"
}]
var projectNames = [];
var projects = [];
for ( i = 0; i < tasks.length; i++) {
if (projectNames.indexOf(tasks[i].project) < 0) {
// checks to see that it's not the projectNames list, and inserts the first entry
projectNames.push(tasks[i].project);
projects.push({
project : tasks[i].project,
tasks : {
name : tasks[i].name
}
});
} else {
// if that project is already in the list, append the next entry
var ind = projectNames.indexOf(tasks[i].project);
projects[ind].tasks.push({
name : tasks[i].name
});
}
}
I'm under the impression that projects[ind].tasks.push()
can't be used, but I'm not sure what the correct thing to replace it with would be?
(Equally if there are any better methods of getting from the first array to the second, I'm always happy to learn something new)
Upvotes: 2
Views: 154
Reputation: 147503
Your problem is here:
projects.push({ project: tasks[i].project, tasks: { name: tasks[i].name } });
You are adding tasks as an object, not an array. You should add it as an array with the object as its sole element:
projects.push({ project: tasks[i].project, tasks: [{ name: tasks[i].name }] });
Below is an alternative solution that might be "better" for some criteria, but for maintainability I think the OP is fine. I've changed the names of the tasks to show that the tasks are assigned to the correct project.
var tasks = [{"name" : "Proj one, Task One", "project" : "Project One"},
{"name" : "Proj two, Task One", "project" : "Project Two"},
{"name" : "Proj one, Task Two", "project" : "Project One"},
{"name" : "Proj one, Task Three", "project" : "Project One"},
{"name" : "Proj two, Task Two", "project" : "Project Two"}
];
var projectNames = [];
var groupedTasks = tasks.reduce(function(acc, obj) {
var projectName = obj.project;
var idx = projectNames.indexOf(projectName);
if (idx == -1) {
projectNames.push(projectName);
idx = acc.projects.length;
acc.projects.push({project:projectName,tasks:[]});
}
acc.projects[idx].tasks.push({name:obj.name});
return acc;
}, {projects:[]});
console.log(groupedTasks);
Upvotes: 1
Reputation: 1115
Since this question is already with a correct answer, i will leave here a function for group by that can be useful to you or anyone that passes here in the future.
var tasks = {
"tasks": [{
"name": "Task One",
"project": "Project One"
}, {
"name": "Task One",
"project": "Project Two"
}, {
"name": "Task Two",
"project": "Project One"
}, {
"name": "Task Three",
"project": "Project One"
}, {
"name": "Task Two",
"project": "Project Two"
}]
};
function groupBy(array, f_gb, f_content) {
var groups = {};
array.forEach(function(o) {
var group = f_gb(o);
groups[group] = groups[group] || [];
if(f_content == null)
groups[group].push(o);
else
groups[group].push(f_content(o));
});
return groups;
}
//An you call the group by like this:
var result = groupBy(tasks.tasks,
// function from what to filter from
function(item) {
return item.project;
},
// optional: what to chose from the object filtered
function(item){
return { name : item.name};
}
);
console.log(result);
Upvotes: 0
Reputation: 386786
You could use Array#forEach
and for thisArg an object, if the same project is already created.
var object = { "tasks": [{ "name": "Task One", "project": "Project One" }, { "name": "Task One", "project": "Project Two" }, { "name": "Task Two", "project": "Project One" }, { "name": "Task Three", "project": "Project One" }, { "name": "Task Two", "project": "Project Two" }] },
result = { projects: [] };
object.tasks.forEach(function (a) {
if (!this[a.project]) {
this[a.project] = { project: a.project, task: [] };
result.projects.push(this[a.project]);
}
this[a.project].task.push({ name: a.name });
}, Object.create(null));
console.log(result);
Upvotes: 2