2

I'm trying to group the raw data from:

items:
[
    {
        category: "blog",
        id      : "586ba9f3a36b129f1336ed38",
        content : "foo, bar!"
    },
    {
        category: "blog",
        id      : "586ba9f3a36b129f1336ed3c",
        content : "hello, world!"
    },
    {
        category: "music",
        id      : "586ba9a6dfjb129f1332ldab",
        content : "wow, shamwow!"
    },
]

to

[
    {
        category: "blog",
        items:
        [
            {
                id      : "586ba9f3a36b129f1336ed38",
                content : "foo, bar!"
            },
            {
                id      : "586ba9f3a36b129f1336ed3c",
                content : "hello, world!"
            },
        ]
    },
    {
        category: "music",
        items:
        [
            {
                id      : "586ba9a6dfjb129f1332ldab",
                content : "wow, shamwow!"
            }
        ]
    }
]

The format like this helps me to print the same category data together in the frontend.

The content of the category field is dynamically, so I'm not sure how do I store it to a temporary object and sort them, any thoughts?

(I can't think a better title for the question, please edit if you got a better title.)

Yami Odymel
  • 1,782
  • 3
  • 22
  • 48
  • With a library like Lodash, it would just be [`_.groupBy(items, 'category')`](https://lodash.com/docs/4.17.3#groupBy) – 4castle Jan 10 '17 at 23:11

3 Answers3

6

You can do it using Array#reduce in one pass:

var items = [{"category":"blog","id":"586ba9f3a36b129f1336ed38","content":"foo, bar!"},{"category":"blog","id":"586ba9f3a36b129f1336ed3c","content":"hello, world!"},{"category":"music","id":"586ba9a6dfjb129f1332ldab","content":"wow, shamwow!"}];

var result = items.reduce(function(r, item) {
  var current = r.hash[item.category];
  
  if(!current) {
    current = r.hash[item.category] = { 
      category: item.category,
      items: []
    };
    
    r.arr.push(current);
  }

  current.items.push({
    id: item.id,
    content: item.content
  });
  
  return r;
}, { hash: {}, arr: [] }).arr;
  
console.log(result);

Or the ES6 way using Map:

const items = [{"category":"blog","id":"586ba9f3a36b129f1336ed38","content":"foo, bar!"},{"category":"blog","id":"586ba9f3a36b129f1336ed3c","content":"hello, world!"},{"category":"music","id":"586ba9a6dfjb129f1332ldab","content":"wow, shamwow!"}];

const result = [...items.reduce((r, { category, id, content }) => {
  r.has(category) || r.set(category, {
    category,
    items: []
  });
  
  r.get(category).items.push({ id, content });
  
  return r;
}, new Map).values()];
  
console.log(result);
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
1

Personally, without any helper libraries, I'd just do this

var step1 = items.reduce((result, {category, id, content}) => {
    result[category] = result[category] || [];
    result[category].push({id, content});
    return result;
}, {});
var result = Object.keys(step1).map(category => ({category, items: step1[category]}));

Which babel converts to

var step1 = items.reduce(function (result, _ref) {
    var category = _ref.category,
        id = _ref.id,
        content = _ref.content;

    result[category] = result[category] || [];
    result[category].push({ id: id, content: content });
    return result;
}, {});
var result = Object.keys(step1).map(function (category) {
    return { category: category, items: step1[category] };
});
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
0

So I just solved the question with the following code (jsfiddle):

// Items
// var items = []

// Create an empty object, used to store the different categories.
var temporaryObject = {}

// Scan for each of the objects in the `items` array.
items.forEach((item) =>
{
    // Create a category in the teporary object if the category
    // hasn't been created.
    if(typeof temporaryObject[item.category] === "undefined")
        temporaryObject[item.category] = []

    // Push the item to the its category of the `temporaryObject`.
    temporaryObject[item.category].push({
        id     : item.id,
        content: item.content
    })
})


// Create a empty array used to stores the sorted, grouped items.
var newItems = []

// Scan for each of the category in the `temporaryObject`
for(var category in temporaryObject)
{
    // Push the new category in the `newItems` array.
    newItems.push({
        category: category,
        items   : []
    })

    // Get the last category index of the `newItems` array,
    // so we can push the related data to the related category.
    var lastItem = newItems.length - 1

    // Scan for the related category in the `temporaryObject` object.
    temporaryObject[category].forEach((item) =>
    {
        // Push the related data to the related category of the `newItems` array.
        newItems[lastItem].items.push(item)
    })
}

// Prints the sorted, grouped result.
console.log(newItems) 
Yami Odymel
  • 1,782
  • 3
  • 22
  • 48