2

I've the following array I need to return only the uniqe ID for example since in this array I have twice id 1 & 3 I need new array with just the first findigs id,

In this example the first 3 entries, how I can use it with maps/filter and not with regular for

var oData = [{
  id: 1,
  ListTypeGroupDescription: 2,
  test: 111,
  test2: 222
}, {
  id: 2,
  ListTypeGroupDescription: 4,
  test: 333,
  test2: 444
}, {
  id: 3,
  ListTypeGroupDescription: 6,
  test: 666,
  test2: 777
}, {
  id:1,
  ListTypeGroupDescription: 99,
  test: 666,
  test2: 777
}, {
  id: 3,
  ListTypeGroupDescription: 99,
  test: 666,
  test2: 777
}];


var data = oData.map(
  function(obj) {
    return obj.id;
  }
);

http://jsfiddle.net/5qu0j8g0/1/

The map is returning only the ID's but I need the all objects

I need this newArray

var oNew = [{
  id: 1,
  ListTypeGroupDescription: 2,
  test: 111,
  test2: 222
}, {
  id: 2,
  ListTypeGroupDescription: 4,
  test: 333,
  test2: 444
}, {
  id: 3,
  ListTypeGroupDescription: 6,
  test: 666,
  test2: 777
}
]
NSS
  • 755
  • 1
  • 11
  • 30

5 Answers5

4

You could filter it with Array#filter and a temporary hash table Object.create(null)) (a really empty object without any prototypes), inside the callback addressed with this.

The filter() method creates a new array with all elements that pass the test implemented by the provided function.

var oData = [{ id: 1, ListTypeGroupDescription: 2, test: 111, test2: 222 }, { id: 2, ListTypeGroupDescription: 4, test: 333, test2: 444 }, { id: 3, ListTypeGroupDescription: 6, test: 666, test2: 777 }, { id: 1, ListTypeGroupDescription: 99, test: 666, test2: 777 }, { id: 3, ListTypeGroupDescription: 99, test: 666, test2: 777 }],
    oNew = oData.filter(function (a) {
        if (!this[a.id]) {
            this[a.id] = true;
            return true;
        }
    }, Object.create(null));

console.log(oNew);

ES6

var oData = [{ id: 1, ListTypeGroupDescription: 2, test: 111, test2: 222 }, { id: 2, ListTypeGroupDescription: 4, test: 333, test2: 444 }, { id: 3, ListTypeGroupDescription: 6, test: 666, test2: 777 }, { id: 1, ListTypeGroupDescription: 99, test: 666, test2: 777 }, { id: 3, ListTypeGroupDescription: 99, test: 666, test2: 777 }],
    oNew = oData.filter((temp => a => !temp[a.id] && (temp[a.id] = true))(Object.create(null)));

console.log(oNew);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • 1
    Firstly this method is by far the best of all answers. I don't think it can get any better in terms of time complexity. It's clever to use the hash table integrated with the filtering function. It cuts down the redundant `indexOf` searches. However i really liked your IIFE invention to throw in the `temp` object since you can not use the `this` with the arrows as intended. I appreciate your try to keep everything self contained within the filter method. Good functional approach. + – Redu Jun 08 '16 at 09:57
1

This could work.

var keys = [];
var data = oData.filter(
  function(obj) {
    if(keys.indexOf(obj.id) == -1) {
       keys.push(obj.id)
       return obj;
    }
  }
);

Note: I have changed .map() to .filter() as well.

phreakv6
  • 2,135
  • 1
  • 9
  • 11
  • data will have the full objects. If you notice, am using `return obj` and not `return obj.id` – phreakv6 Jun 08 '16 at 07:54
  • You don't need to return `obj` or `obj.id` in the `filter` callback function, you just need to return true or false, however when you return true the whole object will be available in the new array. – Ahmad Ibrahim Jun 08 '16 at 08:13
1

This is a modified version from Unique values in an array. It adds a getUniqueByID function to the Array prototype which returns the unique values by ID of your object in the array (Note: This will only work for arrays which are defined like yours):

Array.prototype.getUniqueByID = function(){
   var u = {}, a = [];
   for(var i = 0, l = this.length; i < l; ++i){
      if(u.hasOwnProperty(this[i].id)) {
         continue;
      }
      a.push(this[i]);
      u[this[i].id] = 1;
   }
   return a;
}

console.log(oData.getUniqueByID());
Community
  • 1
  • 1
oberbics
  • 408
  • 4
  • 12
1

Array.map function will return a new array which has the same length(size) as the initial array.
But you need to filter/remain elements with unique id attribute.
Use an auxiliary array (for ids list) as a second argument(thisArg) using Array.forEach function:

var oNew = [];

oData.forEach(function(obj){
    if (this.indexOf(obj['id']) === -1) {  // check if current 'id' was processed previously 
        this.push(obj['id']);
        oNew.push(obj);
    }
}, []);

console.log(JSON.stringify(oNew, 0, 4));

The output:

[
    {
        "id": 1,
        "ListTypeGroupDescription": 2,
        "test": 111,
        "test2": 222
    },
    {
        "id": 2,
        "ListTypeGroupDescription": 4,
        "test": 333,
        "test2": 444
    },
    {
        "id": 3,
        "ListTypeGroupDescription": 6,
        "test": 666,
        "test2": 777
    }
]
RomanPerekhrest
  • 88,541
  • 4
  • 65
  • 105
1

Using ECMAScript 6:

var oData = [{ id: 1, ListTypeGroupDescription: 2, test: 111, test2: 222 }, { id: 2, ListTypeGroupDescription: 4, test: 333, test2: 444 }, { id: 3, ListTypeGroupDescription: 6, test: 666, test2: 777 }, { id: 1, ListTypeGroupDescription: 99, test: 666, test2: 777 }, { id: 3, ListTypeGroupDescription: 99, test: 666, test2: 777 }],
    oNew = oData.filter((obj, index, self) => self.findIndex((o) => { return o.id === obj.id; }) === index);

console.log(oNew);
Yosvel Quintero
  • 18,669
  • 5
  • 37
  • 46