Michael
Michael

Reputation: 13636

How to make Javascript map function not to return specific value?

I have this array and variable:

var freqId = 45;

$scope.frequencies = [{Id:124,name:'qqq'}, 
                      {Id:589,name:'www'}, 
                      {Id:45,name:'eee'},
                      {Id:567,name:'rrr'}]

I use this row to get all id's from array above:

var inspectionsId = $scope.frequencies.map(function (obj) { return obj.Id; })

The result I get is:

var Id's = [124,589,45,567];

I need to change this row:

$scope.frequencies.map(function (obj) { return obj.Id; })

to retrive all id from frequencies array except where Id equal to freqId variable.

For example desired result is:

var inspectionsId = [124,589,567];

Any idea how can I implemet it?

Upvotes: 1

Views: 2100

Answers (4)

T.J. Crowder
T.J. Crowder

Reputation: 1075885

You'll have seen the filter answers. 99.999% of the time, that's the way to go.

If you have a truly massive array and you think it's important to make just a single pass through it, you could give yourself a function combining map and filter:

// A value to use to mean "leave entry out"
Object.defineProperty(Array.prototype, "OMIT", {
  value: {}
});
// The utility function
Object.defineProperty(Array.prototype, "mapFilter", {
  value: function(f, thisArg, omissionFlag) {
    var result = [];
    if (arguments.length < 3) {
      omissionFlag = Array.OMIT;
    }
    Object.keys(this).forEach(function(index) {
      var value = f.call(thisArg, this[index], index, this);
      if (value !== omissionFlag) {
        result.push(value);
      }
    }, this);
    return result;
  }
});

// Using it
var freqId = 45;

var input = [{Id: 124, name: 'qqq'}, {Id: 589, name: 'www'}, {Id: 45, name: 'eee'}, {Id: 567,  name: 'rrr'}];

var output = input.mapFilter(function(obj) {
  return obj.Id == freqId ? Array.OMIT : obj.Id;
});

console.log(output);

This version accepts up to three arguments:

  1. The map/filter function

  2. The value to use as this during callbacks

  3. The value to use to mean "omit this entry," which defaults to Array.OMIT

It calls its callback with the value, index, and array just like forEach and map and such do.

Again, though, I'll emphasize that in the vast, vast majority of cases, filter and then map (or map and then filter if the map makes filtering easier) is the way to go.


That said, a generic "loop with memo" function has broader applicability:

// The utility function
Object.defineProperty(Array.prototype, "memoLoop", {
  value: function(memo, f, thisArg) {
    Object.keys(this).forEach(function(index) {
      f.call(thisArg, memo, this[index], index, this);
    }, this);
    return memo;
  }
});

// Using it
var freqId = 45;

var input = [{Id: 124, name: 'qqq'}, {Id: 589, name: 'www'}, {Id: 45, name: 'eee'}, {Id: 567,  name: 'rrr'}];

var output = input.memoLoop([], function(result, obj) {
  var id = obj.Id;
  if (id != freqId) {
    result.push(id);
  }
});

console.log(output);

It's a bit like Array#reduce but assumes an unchanging memo value (in our case, the new array), which simplifies the callback somewhat.

Upvotes: 1

Mat&#237;as Fidemraizer
Mat&#237;as Fidemraizer

Reputation: 64943

You can also use Array.prototype.reduce to do both filtering and mapping in a single loop:

var freqId = 45;

$scope = {}; // Dummy scope

$scope.frequencies = [{
  Id: 124,
  name: 'qqq'
}, {
  Id: 589,
  name: 'www'
}, {
  Id: 45,
  name: 'eee'
}, {
  Id: 567,
  name: 'rrr'
}]

var result = $scope.frequencies.reduce(function(result, current) {
  if (current.Id != freqId) {
    result.push(current.Id);
  }

  return result;

}, []);

console.log(JSON.stringify(result));

Upvotes: 4

Lukas Hechenberger
Lukas Hechenberger

Reputation: 179

You can use Array.prototype.filter:

var inspectionsId = $scope.frequencies
  .map(function(obj) { return obj.Id; })
  .filter(function(id) { return id !== 45 })

Upvotes: 2

Quentin
Quentin

Reputation: 944556

map is designed to transform data, not filter it. Chain it with filter for the latter.

var freqId = 45;

var input = [{
  Id: 124,
  name: 'qqq'
}, {
  Id: 589,
  name: 'www'
}, {
  Id: 45,
  name: 'eee'
}, {
  Id: 567,
  name: 'rrr'
}];

var output = input.map(function(obj) {
  return obj.Id;
}).filter(function(element) {
  return element != freqId
});

console.log(output);

Upvotes: 2

Related Questions