markreyes
markreyes

Reputation: 1289

Check for duplicate values in an array of object literals and create a new object from them

I currently have any array of object literals which have the potential of coming in to the client-side with duplicate values (see the Date key).

[
    {
        "Date": "2/26/2018",
        "Title": "Story 1"
    },
    {
        "Date": "2/27/2018",
        "Title": "Story 2"
    },
    {
        "Date": "2/27/2018",
        "Title": "Story 3"
    },
    {
        "Date": "2/28/2018",
        "Title": "Story 4"        
    }
]

How could I check the value of the previous key to consolidate this in to 1 new object such as:

[
    {
        "Date": "2/26/2018",
        "Title": "Story 1"
    },
    {
        "Date": "2/27/2018",
        "Stories": {
            [
                {
                   "Title": "Story 2"
                },
                {
                   "Title": "Story 3"
                }
            ]
        }
    },
    {
        "Date": "2/28/2018",
        "Title": "Story 4"        
    }
]

Here's the kicker - no frameworks such as Underscore.js can be used.

Thoughts?

Upvotes: 0

Views: 125

Answers (3)

guijob
guijob

Reputation: 4488

Once you just want to create a Stories object when it has titles to be grouped I think this should work:

arr.reduce((acc, ele) => {
    if(acc.length == 0) return acc.concat(ele);
    var previous = acc[acc.length - 1];
    if(ele.Date == previous.Date) {
        if(!previous.Stories) previous.Stories = [{ title: previous.Title }];
            previous.Stories.push({ title: ele.Title })
            delete previous.Title;
        return acc;
    }
return acc.concat(ele);
}, [])

Upvotes: 0

Zerium
Zerium

Reputation: 17333

I think you need to break down the problem a bit more.

This is very similar to a GROUP BY statement in SQL - essentially, you're grouping by Date in this situation.

I would do it like so:

function parseStories(stories) {
  // we're going to record previous stories in an object using their date, as that is the value we wish to group by
  var previousStories = {};
  stories.forEach(function (storyObj) {
    // this is how we should insert the object - it fits the "shape" of object retrieval where there is more than 1 result
    var insertObj = { Title: storyObj.Title };
    if (previousStories[storyObj.Date]) {
      // date already exists
      previousStories[storyObj.Date].push(insertObj);
    } else {
      // new date
      previousStories[storyObj.Date] = [insertObj];
    }
  });

  // we generate the return result
  var returnResult = [];
  // NOTE - object property order is not guaranteed; however, you can mitigate this by using an array to sort the keys if you so wish
  for (var key in previousStories) {
    if (previousStories[key].length > 1) {
      // if we have more than one story on a day, we can just add this to the Stories property
      returnResult.push({
        Date: key,
        Stories: previousStories[key]
      });
    } else if (previousStories[key].length === 1) {
      // if we only have one story, the structure of the return object changes slightly
      returnResult.push({
        Date: key,
        Title: previousStories[key][0].Title
      });
    }
  }

  return returnResult;
}

There is quite a fair bit of logic involved in your grouping; where there is only a single element, the structure of the object you want produced changes subtly, from having a Stories array to having a singular Title property containing the title of that one story. Perhaps this design could be improved upon? It is generally easier to code upon a single data structure, as opposed to one that changes based on the plurality of its content.

Upvotes: 0

Ele
Ele

Reputation: 33726

You can use the function reduce

var array = [    {        "Date": "2/26/2018",        "Title": "Story 1"    },    {        "Date": "2/27/2018",        "Title": "Story 2"    },    {        "Date": "2/27/2018",        "Title": "Story 3"    },    {        "Date": "2/28/2018",        "Title": "Story 4"            }];

var result = Object.values(array.reduce((a, c) => {
  if (a[c.Date]) {
    a[c.Date].Stories.push({Title: c.Title});
  } else {
    a[c.Date] = { "Date": c.Date, "Stories": [{Title: c.Title}] };
  }
  
  return a;
}, {}));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 2

Related Questions