2013-10-13 2 views

Antwort

61

auf mehrere Eigenschaften zu projizieren, müssen Sie map, zupfen nicht:

var results = _.map(
    _.where(people, {city : "ny"}), 
    function(person) { 
     return { firstName: person.firstName, qty: person.qty }; 
    } 
); 

[{ "firstname": "Thein", "Menge": 5}, { "firstname": "Michael “,‚Menge‘: 3}]

(Fiddle)

Beachten Sie, dass, wenn man wollte, könnte man eine Hilfsmethode erstellen‚pluckMany‘, die die gleiche Sache wie zupfen tut mit variabler arg uments:

// first argument is the source array, followed by one or more property names 
var pluckMany = function() { 
    // get the property names to pluck 
    var source = arguments[0]; 
    var propertiesToPluck = _.rest(arguments, 1); 
    return _.map(source, function(item) { 
     var obj = {}; 
     _.each(propertiesToPluck, function(property) { 
      obj[property] = item[property]; 
     }); 
     return obj; 
    }); 
}; 

können Sie die _.mixin Funktion verwenden, um eine "pluckMany" -Funktion zum _ Namespace hinzuzufügen. Mit diesem können Sie schreiben einfach:

var results = _.chain(people).where({city : "ny"}).pluckMany("firstName", "qty").value(); 

(Fiddle)

+0

Dank McGarnagle; Um Parameter an pluckMany zu übergeben, ist es gut Array zu übergeben? Ich bin ein Neuling und denke darüber nach, Unterstreichung zu übernehmen. Ich denke Mixin ist äquivalent zu jquery plugin (fn). – ttacompu

+0

@ttacompu Wie ich es geschrieben habe, musst du 1) Array und 2) mehrere Argumente übergeben. Sie könnten es ändern, um entweder mehrere Argumente oder ein Array als zweiten Parameter zu akzeptieren ... – McGarnagle

4

Mein Verständnis ist der Autor der Frage möchte ein Array von Objekten mit vielen Eigenschaften nehmen und jede auf eine kleine Liste von Objekteigenschaften nach unten abzustreifen.

Es gibt unzählige Möglichkeiten, dies mit _ zu tun, aber ich mag diesen Weg am besten. Übergeben Sie ein leeres Ergebnisobjekt, das innerhalb der Funktion "this" sein wird. Iterate mit _each und _pick die Felder, die Sie wollen:

var myObjects = [ 
    { "first" : "eric", 
     "last" : "gumbo", 
     "code" : "x482" 
    }, 
    { "first" : "john", 
     "last" : "dinkman", 
     "code" : "y9283" 
    } 
]; 

var result = []; 
_.each(myObjects, function(itm) { this.push(_.pick(itm,"first","code")) }, result); 

console.log(result); 
+1

Warum push zu einem unnötigen Array innerhalb jedes einzelnen anstatt nur Karte verwenden? –

16

TL; DR Verwendung:

var results = _.chain(people) 
    .where({ city: "ny" }) 
    .map(_.partialRight(_.pick, 'firstName', 'qty')) 
    .value(); 

Aber lesen Sie bitte weiter nach Erklärungen, wie ich den Prozess des Findens dieser Lösung fühlen interessanter als die tatsächliche Antwort.


Das allgemeine Muster wäre (es funktioniert mit lodash auch):

_.map(array, function(obj) { return _.pick(obj, 'x', 'y', 'z'); });

diese allgemeine map Funktion gegeben, die jedes Element einer Sammlung verwandelt, gibt es mehrere Möglichkeiten anzupassen, dies zu Ihre besondere Situation (das bürgt für die Flexibilität von map, die ein sehr grundlegender Baustein funktionaler Programme ist).

Lassen Sie mich unter mehreren Möglichkeiten vorhanden unsere Lösung zu implementieren:

var _ = require('lodash'); // @lodash 2.4.1 at the time of writing 
// use underscore if you want to, but please see http://stackoverflow.com/questions/13789618/differences-between-lodash-and-underscore 


/* la data */ 
var people = [{ 
    firstName: "Thein", 
    city: "ny", 
    qty: 5 
}, { 
    firstName: "Michael", 
    city: "ny", 
    qty: 3 
}, { 
    firstName: "Bloom", 
    city: "nj", 
    qty: 10 
}]; 


/* OPTION1 : mixin' with _ */ 
_.mixin({ 
    pluckMany: function() { 
     var array = arguments[0], 
      propertiesToPluck = _.rest(arguments, 1); 

     return _.map(array, function(item) { 

      /* Alternative implementation 1.1 
      * ------------------------------ 
      * Taken from @mMcGarnagle answer 
      * _each is easy to understand here, 
      * but has to modify the variable `obj` from a closure 
      * I try to avoid that for trivial cases like this one. 
      */ 
      var obj = {}; 
      _.each(propertiesToPluck, function(property) { 
       obj[property] = item[property]; 
      }); 
      return obj; 


      /* Alternative implementation 1.2 
      * ------------------------------ 
      * Rewrite the previous code, 
      * by passing the accumulator (previously`obj`, but really it is an object that accumulates the result being constructed) across function calls. 
      * This construction is typical of the `reduce` function, closer to a functionnal programming style. 
      */ 
      return _.reduce(propertiesToPluck, function(obj, property) { 
       obj[property] = item[property]; 
       return obj; 
      }, {}); 


      /* Alternative implementation 1.3 
      * ------------------------------ 
      * If we are already using lodash/underscore, 
      * then let's use the `pick` function ! I also included an example of `flatten` here 
      */ 
      return _.pick(item, _.flatten(propertiesToPluck, true)); 


      /* Alternative implementation 1.4 
      * ------------------------------ 
      * But really flatten is not needed. 
      */ 
      return _.partial(_.pick, item).apply(null, propertiesToPluck); 
     }); 
    } 
}); 



/* Let's use our mixed function ! 
* Since we call several _ functions on the same object 
* it is more readable to chain the calls. 
*/ 
var results = _.chain(people) 
    .where({ 
     city: "ny" 
    }) 
    .pluckMany('firstName', 'qty') 
    .value(); 



/* OPTION 2 : without mixing our code with lodash/underscore */ 
var results = _.chain(people) 
    .where({ 
     city: "ny" 
    }) 
    .map(_.partialRight(_.pick, 'firstName', 'qty')) 
    .value(); 

console.log(results); 

Wenn Sie mit underscore oder lodash schreiben Codes wie diese Weise sehr ich vorschlagen, dass Sie einen Blick auf funktionale Programmierung, haben als Diese Art des Schreibens sowie viele Funktionen (map, reduce unter vielen anderen) kommen von dort.

Hinweis: Dies ist offenbar eine häufig gestellte Frage in Strich: https://github.com/jashkenas/underscore/issues/1104

Dies ist offenbar kein Zufall, wenn diese aus sind links von Unterstrichen/lodash: „composability ist besser als Merkmale“. Sie könnten auch do one thing and do it well sagen. Dies ist auch der Grund, warum _.mixin existiert.

+2

Umm, also sollte dies die richtige Antwort sein :) Auch Pick kann benutzerdefinierte Funktionen für Whitelist/Blacklisting Requisiten behandeln. – David

+1

Re 'Komponierbarkeit ist besser als Features': Die Antwort selbst verwendet _.pick mit mehreren Eigenschaften. Mit der obigen Argumentation gäbe es dafür kein Merkmal, oder _.pluck würde gar nicht existieren, da die obige Lösung (map..pick) auch mit einer Eigenschaft perfekt funktionieren würde. Es fühlt sich also ungleichmäßig an, dass Zupfen nicht mehrere Tasten unterstützt, sondern Auswählen. –

+1

Dies ist erstaunlich - bei weitem die eleganteste Art, dies hier vorgeschlagen zu tun. Es hat auch den zusätzlichen Vorteil einer außergewöhnlich guten Zusammensetzbarkeit - es ist super einfach, Schritte aus dem Prozess hinzuzufügen und zu entfernen. Viele Kudos. –

3

Ja, ich wünsche pluck eine Option hatte eine Reihe von vorbei, aber in der Zwischenzeit könnten Sie tun:

function pluckFields(arr, fields) { 
    return _.map(arr, function(item) { 
    return _.pick(item, fields) 
    }) 
} 
0

Dass man linear einige Zeilen sparen könnten:

var results=_.pick(_.where(people, {city : "ny"}), 'firstName', 'qty'); 
-1

Wir don Müssen Sie nicht zupfen, lassen Sie es nicht auch tun.

var result = _.map(people, function(person) { 
    return _.omit(person, 'city'); 
}); 
0

YAAUu -Yep Noch eine Lösung Mit Strich ...

// use a proper browser to run this code snippet, a browser that is es6-compliant 
 
let people = [{ 
 
    firstName: "Thein", 
 
    city: "ny", 
 
    qty: 5 
 
    }, 
 
    { 
 
    firstName: "Michael", 
 
    city: "ny", 
 
    qty: 3 
 
    }, 
 
    { 
 
    firstName: "Bloom", 
 
    city: "nj", 
 
    qty: 10 
 
    } 
 
]; 
 
// either you pick the properties you want 
 
let picking = _.iteratee((person) => _(person).pick("firstName", "city")); 
 
// either you omit the properties you do not want 
 
let omitting = _.iteratee((person) => _(person).omit("qty")); 
 
// create the filter by city 
 
let living = (people, city) => _(people).where({ 
 
    "city": city 
 
}); 
 
// put the "filter by city" into a mixin (as I assume it would be used again & again) 
 
_.mixin({ 
 
    living: living 
 
}); 
 
// do the thing (twice), 
 
// these chaining methods could be done into a mixin as well 
 
console.log("results by picking properties:", _(people).chain().living("ny").map(picking).value()); 
 
console.log("results by omitting properties:", _(people).chain().living("ny").map(omitting).value());
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>