0xPingo
0xPingo

Reputation: 2207

Merge arrays with underscore.js

After performing a few underscore.js operations (_.map, _.each, _.pluck, and _.flatten), I have an array of objects that looks like this:

var userArray = [
  {id: 123456, username: "bill123", group: "ONE"},
  {id: 123457, username: "joe123", group: "TWO"},
  {id: 123457, username: "joe123", group: "TWO"},
  {id: 123458, username: "jim123", group: "ONE"}
]

I need to create a new array, with duplicates removed, and a count of how many times the object appeared in the array. I am able to get the desired results with two separate underscore.js functions, but am having trouble merging the two results.

The working functions are as follows:

var uniqUsers = _.uniq(taggedUsers, false, function(user) {
  return user.id
});
  //returns array of unique objects in the same format as above
  //[{id: 123457, username: "joe123", group: "TWO"},...]

var userCounts = _.countBy(taggedUsers, "id");
  //returns the count for each user in the userArray in a single object
  //{123456: 1, 123457: 2, 123458: 1}


What's the best approach for returning an array of objects like this:

{id: 123457, username: "joe123", group: "TWO", count: 2}

Can I add additional fields to the _.countBy function? Or do I need to do something with _.map?

Any help would be greatly appreciated ! Thanks

Upvotes: 1

Views: 1788

Answers (2)

Anid Monsur
Anid Monsur

Reputation: 4538

You can use map on userCounts to create a new array which you can then sort.

var userArray = [
  {id: 123456, username: "bill123", group: "ONE"},
  {id: 123457, username: "joe123", group: "TWO"},
  {id: 123457, username: "joe123", group: "TWO"},
  {id: 123458, username: "jim123", group: "ONE"}
];

var userCounts = _.countBy(userArray, "id");

var result = _.sortBy(_.map(userCounts, function(count, id) {
  var user = _.findWhere(userArray, {id: Number(id)});  
  return _.extend({}, user, {count: count});
}), 'count');

console.log(result);

Result:

[[object Object] {
  count: 1,
  group: "ONE",
  id: 123456,
  username: "bill123"
}, [object Object] {
  count: 1,
  group: "ONE",
  id: 123458,
  username: "jim123"
}, [object Object] {
  count: 2,
  group: "TWO",
  id: 123457,
  username: "joe123"
}]

JSBin

Upvotes: 4

Vinay
Vinay

Reputation: 6332

I would just do it in two _.eachs:

var uniquedUsersWithCount = [],
    userIDToCount = {};

_.each(taggedUsers, function (user) {
  if (userIDToCount[user.id] !== undefined) {
    userIDToCount[user.id] += 1;
  } else {
    userIDToCount[user.id] = 0;
    uniquedUsersWithCount.push(user);
  }
});

_.each(uniquedUsersWithCount, function (user) {
  var count = userIDToCount[user.id];
  if (count !== undefined) {
    user.count = count;
  }
});

Upvotes: 3

Related Questions