0

I am making some checking between array. It is in NodeJS.

The question is:

I have an array:

var items = [];

than I insert some values into it:

items[0] = {a:1, b:222};
items[1] = {a:1, b:333};
items[2] = {a:1, b:222};
items[3] = {a:1, b:4444};
items[4] = {a:1, b:222};

So, what I need to do is: to go threw all array and remove item's that has the same 'b' value.

Example:

After filtering, it should look like:

items[0] = {a:1, b:222};
items[1] = {a:1, b:333};
items[2] = {a:1, b:4444};

As you see elements with indexes 2 and 4 gone, because they has the same b value as element at index 0.

How can I write this little code in JavaScript?

3 Answers3

2

You're looking for an Array.prototype.filter function:

var bValues = {};
items = items
    .filter(function(item) {
        return bValues[item.b] === undefined && (bValues[item.b] = true);
    });

This works by checking if we have seen a particular bValue, and returning false if we have. If we haven't, we set that value on the bValues map and return true.

Edit: I like the nifty suggestion of @dandavis, using the this binding parameter to reduce variable names:

items = items
    .filter(function(item) {
        return this[item.b] === undefined && (this[item.b] = true);
    }, {});
TbWill4321
  • 8,626
  • 3
  • 27
  • 25
  • 1
    one suggestion; instead of defining an extra var and reaching it via closure, pass `{}` as the 2nd argument to filter() and change `bValues` inside to `this`. keeping it pure helps re-usability and performance. – dandavis Oct 20 '15 at 16:39
  • @dandavis That's cute. –  Oct 20 '15 at 17:09
  • @dandavis That's a cool idea. Added it to answer. – TbWill4321 Oct 20 '15 at 20:12
0

If I understand your question correctly, you want to do a pass to remove every single duplicate b value. This is actually more of an algorithm question than a Javascript question. There are lot of ways to do this, but my answer is going to focus on performance.

Here is one of the faster ways to do this in Javascript (O(n)):

var items = [];
// Insert a bunch of items with signature {a: Number, b: Number}
items = removeDuplicatesOfB(items);

function removeDuplicatesOfB(items) {
  var map = {};
  var filtered = [];
  items.forEach(function (item) {
    if (!map[item.b]) {
      filtered.push(item);
      map[item.b] = true;
    }
  });
  return filtered;
}

At this point you could focus on abstracting out the duplicate removal to make this a reusable function.

JoshuaJ
  • 929
  • 1
  • 9
  • 22
0

All the answers propose roughly equivalent algorithms, so it boils down to what is most understandable. Here's one idea. We'll start off by describing the algorithm in English:

  1. Of all the items, keep those with the first b.
  2. For an item, "first b" means the index of this item is equal to the index of the first element whose b property is equal to the b property of the item.

Now we can pretty much transform that English into JavaScript.

function removeDuplicatesOfB(items) {

  // Is this item the first in the array with its b property?
  function firstB(item, idx) { 
    return idx                 // The index of this item
      ===                      // equal to
      items.findIndex(         // the index of the first
       e =>                    // element 
         e.b                   // whose b property
         ===                   // is equal to
         item.b                // the b property of the item.
      )
    ;
  }


  return items .               // Of all the items,
    filter(                    // keep those with
      firstB                   // the first b.
    )
  ;
}

Or, in non-commented form:

function removeDuplicatesOfB(items) {

  function firstB(item, idx) {
    return idx === items.findIndex(e => e.b === item.b);
  }

  return items.filter(firstB);
}

Underscore

Underscore's _.uniq can do this in its sleep, by passing it a "predicate" telling it how to compare the objects for purposes of determining whether they are the "same":

_.uniq(items, function(item) { return item.b; })