difficult title for a simple issue 🙂
say we have a list of books
they are in different categories, these categories are an array property on the book
we want to transform this json, into a list of unique categories, with the books under the category
first off: the json:
[
{
"description":"book 1 description",
"title":"book 1 title",
"id":"4",
"logo":"",
"image":"",
"categories":[
{
"id":"1",
"title":"Logistiek"
},{
"id":"2",
"title":"Finances"
}
]
},
{
"description":"book 2 description",
"title":"book 2 title",
"id":"1",
"logo":"",
"image":"",
"categories":[
{
"id":"3",
"title":"Telecom"
}
]
},
{
"description":"book 3 description",
"title":"book 3 title",
"id":"2",
"logo":"",
"image":"",
"categories":[
{
"id":"3",
"title":"Telecom"
}
]
},
{
"description":"book 4 description",
"title":"book 4 title",
"id":"3",
"logo":"",
"image":"",
"categories":[
{
"id":"2",
"title":"Finances"
}
]
}
]
now what i managed myself:
i started by mapping off all the categories:
var data = {} // lets say all json is inhere...
var res = _(data).map(function(m){
return m.categories;
});
this I flatten into 1 array of categories (because now its an array per book.
res = _(res).flatten();
this gives me an array of all category items, though this has doubles in it.
now i’m not getting much further than this yet.
i tried using the union method before flattening but that didnt help out
i tried the uniq on the bigger array but i think i have to break em down into separate arrays for the uniq to work
i’m kind of stuck getting the unique values out of that array of categories.
after that I can manage to add the books under the categories
If anyone got some ideas, or maybe tell me that i’m doing this completely wrong 🙂 go ahead tell me, if i can do it shorter or with better performance by going another direction feel free to throw it at me.
update1
ok, now i got a little further but i’m pretty sure it’s not ideal, (too many steps, i get a feeling getting a unique list could go quicker than these steps)
// get all categorie arrays
var res = _(data).map(function(m){
return m.categories;
});
// flatten them
res = _(res).flatten();
// reduce to unique ID array
var catIds = _(res).pluck('id');
catIds = _(catIds).uniq();
// from here on create an array with unique categories
var cats = [];
_(catIds).each(function(cId){
var s = _(res).filter(function(c){
return c.id === cId;
});
cats.push(_(s).first());
});
can I do this quicker?
see jsFiddle in action…
http://jsfiddle.net/saelfaer/JVxGm/
update 2
ok, i got further, thanks to the help from you guys below,
but i still feel like using 2 eaches is not the best way to get to the end.
var json = [] // lets say the above json is in this variable.
var books = _(json).map(function(book) {
var cats = book.categories;
delete book.categories;
return _(cats).map(function(cat) {
return _({}).extend(book, { category: cat });
});
});
books = _(books).flatten();
var booksPerCategory = [];
_(books).each(function(book){
if(!_(booksPerCategory).any(function(cat){
return cat.id === book.category.id;
}))
{ booksPerCategory.push(book.category); }
});
_(booksPerCategory).each(function(cat){
var mods = _(books).filter(function(book){
return book.category.id === cat.id;
});
cat['modules'] = mods;
});
you can see what i wanted to recieve: the booksByCategory array
and what i got via the help from below: the books object
both in this jsfiddle: http://jsfiddle.net/saelfaer/yWCgt/
You could do something like this:
Demo: http://jsfiddle.net/ambiguous/jaL8n/
If you only want a slice of each book’s attributes then you can adjust this:
accordingly; for example, if you just want the titles and category IDs:
Demo: http://jsfiddle.net/ambiguous/EFLDR/
You don’t need to explicitly generate a set of unique category IDs, you just have to arrange your data appropriately and everything falls out on its own (as is common with functional approaches).
UPDATE: Based on the comments, I think you just need to add a
reduceafter theflatteninstead of agroupBy:Demo: http://jsfiddle.net/ambiguous/vJqTz/
You could also use
chainand some named functions to make it easier to read:Demo: http://jsfiddle.net/ambiguous/kSU7v/