46

I'm trying to recreate the Underscore pluck function using pure JS. However, I keep getting an array of undefineds being returned, instead of the actual values from the properties of the objects in an array.

Checking another thread here I found that you could reproduce it in jQuery with the following code...

$.pluck = function(arr, key) { 
    return $.map(arr, function(e) { return e[key]; }) 
}

...however I am having difficulty just reproducing this in pure JS. I tried the following, however this is just returning an array of undefineds for me.

var pluck = function(arr,key){
  var newArr = [];
  for (var i = 0, x = arr.length; i < x; i++){
    if (arr[i].hasOwnProperty(key)){
      newArr.push(arr[i].key)
    }
  }
  return newArr;
}

So, the goal would be the following, except instead of using the underscore _.pluck, just use a JS function name, eg. var pluck = function(arr,key){...}

var Tuts = [{name : 'NetTuts', niche : 'Web Development'}, {name : 'WPTuts', niche : 'WordPress'}, {name : 'PSDTuts', niche : 'PhotoShop'}, {name : 'AeTuts', niche : 'After Effects'}];
var niches = _.pluck(Tuts, 'niche');

console.log(niches);

// ["Web Development", "WordPress", "PhotoShop", "After Effects"]

Could someone steer me in the right direction?

Community
  • 1
  • 1
wesleysmyth
  • 4,348
  • 2
  • 17
  • 17
  • 2
    The nice thing about Underscore is that its source code is available online in annotated form, so it’s quite easy to read it and see what they do. Here’s [the source for `_.pluck()`](http://underscorejs.org/docs/underscore.html#section-27), although it’s mainly composed of [`_.map()`](http://underscorejs.org/docs/underscore.html#section-17) and [`_.property()`](http://underscorejs.org/docs/underscore.html#section-131). – Paul D. Waite Sep 08 '14 at 14:20
  • Adding to the above, there is nowadays a modular version of the annotated source. Here is [the `_.pluck` module](https://underscorejs.org/docs/modules/pluck.html). – Julian Feb 19 '22 at 21:27

10 Answers10

79

In ES5:

function pluck(array, key) {
  return array.map(function(obj) {
    return obj[key];
  });
}

In ES6:

function pluck(array, key) {
  return array.map(o => o[key]);
}
Gilles Castel
  • 1,144
  • 11
  • 15
19

You can do it with the native JavaScript .map():

Array.prototype.pluck = function(key) {
  return this.map(function(object) { return object[key]; });
};

edit — modifying built-in prototype objects should be done with care; a better way to add the function (should you be OK with the idea of doing so in general) would be with Object.defineProperty so that it can be made non-enumerable:

Object.defineProperty(Array.prototype, "pluck", {
    value: function(key) {
        return this.map(function(object) { return object[key]; });
    }
});
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • @NULL no "need" really, but if `.map()` is on the prototype it's symmetric for `.pluck()` to be there. However I'll ammend the answer with the right way to add it. – Pointy Sep 08 '14 at 14:08
  • @NULL I agree, but it depends on the environment. I don't like using libraries that do this (even though I otherwise really liked Prototype back in the day), but if I'm confident that I'm the only one doing it in a project, it is a convenience and it can make code cleaner. I have used the trick only very rarely however. – Pointy Sep 08 '14 at 14:12
8

You are so close. You need to change:

newArr.push(arr[i].key);

to:

newArr.push(arr[i][key]);

Consider this:

var obj = { myKey: 'my Value', theKey: 'another value' };
var theKey = 'myKey';

alert(obj.theKey); // another value
alert(obj[theKey]); // my Value
// You can also send in strings here:
alert(obj['theKey']); // another value

Hope you get my point.

Andreas Louv
  • 46,145
  • 13
  • 104
  • 123
  • 1
    Amazing, thanks! I got it to work...And I believe I understand this concept now. Each arr[i] object does not necessarily have a .key property... Instead the key value being passed to the pluck function needs to be passed using the bracket notation, ensuring that you are attempting to access the correct property of the object given to the pluck function as the second argument. Does this sound right? – wesleysmyth Sep 08 '14 at 14:24
  • 1
    Yes, when using bracket notation you can use variables as the key you are trying to access, while using dot notation the key will be what you write. This also helps you when dealing with keys with dots, spaces reserved words etc. `obj['my weird key...']` is valid while `obj.my weird key...` will throw a syntax error. You will also need to write `obj['enum']`, `obj['catch']` when targeting < IE9 – Andreas Louv Sep 08 '14 at 14:37
2

Here's an example of doing _.pluck(Tuts, 'name');

const Tuts = [{name : 'NetTuts', niche : 'Web Development'}, {name : 'WPTuts', niche : 'WordPress'}, {name : 'PSDTuts', niche : 'PhotoShop'}, {name : 'AeTuts', niche : 'After Effects'}];


const pluckedNames = Tuts.map(({ name }) => name);

If you want to remove the undefined values in the case that there is no name in the object, you can use a .filter() afterward

const pluckedNames = Tuts.map(({ name }) => name).filter(i => i);
seantomburke
  • 10,514
  • 3
  • 18
  • 23
1

Just plain simple without the need to use methods:

var pluck = function (arr, key) {
  var newArr = [];
  for (let i = 0; i < arr.length; i++) {
    newArr.push(arr[i][key]);
  }
  return newArr;
};
dr3nan
  • 37
  • 1
  • 8
0

Here's a working solution

function pluck(array,key){
  var a = [],
     i1 = -1, i2 = array.length,
      o ;

    while(++i1 < i2)
    {
        o = array[i1] ; // you have to use the bracket operator here
        if(o.hasOwnProperty(key)) a[a.length] = o[key] ;
    }
  return a ;
}

I didn't really change all that much. The reason why your code failed is because you used the dot operator .key to access the named property of the array elements instead of the bracket operator [key]. When using a reference as a key you need to use the bracket operator.

FK82
  • 4,907
  • 4
  • 29
  • 42
0

How about using Proxy?

f = new Proxy(x => x, {
    get: (_,prop) => x => x[prop]
})

Here's an example of doing _.pluck(Tuts, 'name');

const Tuts = [{name : 'NetTuts', niche : 'Web Development'}, {name : 'WPTuts', niche : 'WordPress'}, {name : 'PSDTuts', niche : 'PhotoShop'}, {name : 'AeTuts', niche : 'After Effects'}];
const pluckedNames = Tuts.map(f.name);

If you want to remove the undefined values in the case that there is no name in the object, you can use a .filter() afterward

const pluckedNames = Tuts.map(f.name).filter(f);
JakubJ
  • 31
  • 2
0

This is combined function for some cases when you need an object with key value:

const pluck = (array, value, key = null) => {
    const newArray = key ? {} : [];

    array.forEach((item) => {
        if (key) {
            newArray[item[key]] = item[value];
        } else {
            newArray.push(item[value]);
        }
    });

    return newArray;
}

Example:

const a = [
    {key1: 'value1', key2: 'value2'}, 
    {key1: 'value3', key2: 'value4'},
];
const result = pluck(a, 'key2', 'key1');

It will return:

{value1: 'value2', value3: 'value4'}
SpinyMan
  • 436
  • 5
  • 9
-1

How about a reduce:

$.pluck = function(arr, key) { 
    return arr.reduce(function(p, v) { 
      return p.concat(v[key]); 
    }, []); 
}

var people = [
  { name: 'James', age: 26 }, 
  { name: 'Fred', age: 56 }
];

$.pluck(people, 'age');
=> [26, 56]

$.pluck(people, 'name');
=> ['James', 'Fred']
Jivings
  • 22,834
  • 6
  • 60
  • 101
-4
var array = {
name: ["Pedro", "João", "Francisco", "Diogo"],
ID: [1,2,3,4]
};
console.log(pluck(array,'name'));

function pluck(array, key) {
   return (array[key]);
};

JSFiddle

You can use this function, click in JSFiddle to see a Example!! :)

Community
  • 1
  • 1
  • 1
    This does not help, usually the array will be structured like so `[{id: 1, name: 'Pedro'}, {id: 2, name: 'Joao'}]` – brettwhiteman Aug 30 '17 at 00:08
  • var array = [{ name: ["Pedro", "João", "Francisco", "Diogo"], ID: [1,2,3,4] },{ name: ["Jose", "Maria", "Bruno", "Rui"], ID: [1,2,3,4] }]; console.log(pluck(array[1],'name')); function pluck(array, key) { return (array[key]); }; Did help now? – Pedro Monteiro Arantes Dec 20 '17 at 17:11