2016-09-20 3 views
0

Zunächst bin ich ziemlich neu in Streams, so dass ich mich immer noch mit einigen gängigen Mustern beschäftige.Wie gruppieren Sie einen Stream, und bearbeiten Sie dann die Gruppen separat basierend auf dem Schlüssel der Gruppe?

In vielen Bibliotheken können wir einen Stream in einen Strom von Streams aufteilen, indem wir .groupBy (keySelectorFn) verwenden. Beispielsweise wird dieser Strom in Ströme aufgeteilt, basierend auf dem Wert von ‚a‘ in jedem Objekt (Pseudo-Code, an einem bestimmten Bibliothek basierte nicht):

var groups = Stream.of(
    { a: 1, b: 0 }, 
    { a: 1, b: 1 }, 
    { a: 2, b: 2 }, 
    { a: 1, b: 3 } 
) 
.groupBy(get('a')); 

Say I Gruppen wollen anders verarbeiten, basierend auf dem Wert von ‚a‘ dieser Gruppe:

groups.map(function(group) { 
    if (..?) { 
     // Run the group through some process 
    } 

    return group; 
}); 

ich kann nicht sehen, wie der Wert von ‚a‘ erhalten, ohne das erste Element jeder Gruppe raubend (und wenn das erste Element einer Gruppe verbraucht wird, um die Gruppe ist nicht mehr intakt).

Dies scheint mir eine ziemlich häufige Sache, die ich mit Streams machen möchte. Gehe ich falsch?

--- EDIT ---

Hier ist ein spezifischeres Beispiel für ein Problem, das ich auf bin stecken:

var groups = Stream.of(
    { a: 1, b: 0 }, 
    { a: 1, b: 1 }, 
    { a: 2, b: 0 }, 
    { a: 2, b: 1 }, 
    { a: 2, b: 2 }, 
    { a: 1, b: 2 } 
) 
.groupBy(get('a')); 

Wie das erste 1-Objekt auszuwählen, in dem ein === 1 , und die ersten 2 Objekte, wo a === 2, und andere Objekte gerade durchgehen? Dies scheint logisch zu mir:

groups.chain(function(group) { 
    return group.key === 1 ? 
     group.take(1) : 
    group.key === 2 ? 
     group.take(2) : 
     group ; 
}); 

Aber group.key nicht existiert (und selbst wenn es täte, würde es ein bisschen ... stinkende scheinen).

+0

Suchst du so etwas ?: http://jsbin.com/haliqerita/edit?js,console –

Antwort

0

groupBy gibt Ihnen einen Stream von Streams (jeder Wert im Stream ist ein Stream selbst). Mit fold können Sie jede Gruppe (die ein Stream ist) zu einem einzigen Wert verarbeiten (unter Verwendung von Bedingungen). flatMap bringt alle Ergebnisse in einen einzigen Stream. Hier ist ein einfaches Beispiel, das Gruppen von Objekten verarbeitet. Sie gruppiert die Objekte gemäß der Eigenschaft "a", führt eine arithmetische Operation basierend auf dem Wert in einem einzelnen Objekt aus, das die Eigenschaften type und val enthält. Diese abschließenden Objekte werden in einen einzigen Strom abgeflacht:

 
var groupStream = Bacon.fromArray([ 
    { a: 1, b: 0 }, 
    { a: 1, b: 1 }, 
    { a: 2, b: 2 }, 
    { a: 1, b: 3 } 
]); 

// -----[stream of objects where a=1]-------[stream of objects where a=2]----> 
var groups = groupStream.groupBy(function(k){ return k.a; }) 

// v is a stream of a=1 objects or a=2 objects 
groups.flatMap(function(v) { 

//fold(reduce) over the values in v (stream) 
    return v.fold({type:'', val: 0},function(acc,i) { 
    if(i.a == 1) { 
     return {type: 'one', val: acc.val + i.b }; 
    } 

    if(i.a == 2) { 
     return {type: 'two', val: acc.val + i.b }; 
    } 
    }) 
}).onValue(function(v) { 
    console.log(v); 
}); 

Hier ist die jsbin: http://jsbin.com/haliqerita/edit?js,console

Hoffnung, das hilft.

+0

Richtig, ok. Ich kann sehen, dass mit .fold() (oder .reduce()) ist vielleicht der Weg nach vorne. Aber Sie haben bedingte Prüfungen für die Eigenschaft 'a' innerhalb .fold() ... da Sie GroupStream bereits mit dem Wert von 'a' gruppiert haben, scheint es ein wenig verschwenderisch zu sein, dann jedes Objekt in diesen Gruppen nach dem Wert zu überprüfen von 'a'. Eine der Sachen, die Leute über Ströme trompeten, ist ihre Effizienz. Zugegeben, ein kleiner Scheck ist keine große Sorge, aber ich bin überrascht von dieser Art von Sache. – stephband

+0

Nun stelle ich mir vor, dass ich das erste 1 Objekt mit a === 1 nehmen möchte, aber die ersten 2 Objekte, bei denen a === 2. .fold() hilft hier nicht wirklich, es sei denn, ich habe einige incrementable counter var drin. flatMap - eigentlich würde ich für jeden Wert von 'a' eine Counter-Var benötigen (und ich weiß vielleicht nicht, wie viele Werte von 'a' es gibt). Idealerweise möchte ich tun, wenn (v.key === 1) {return v.take (1); } if (v.key === 2) {return v.take (2); } ... aber es gibt keine v.key ... – stephband

+0

Ich habe der Frage ein Beispiel hinzugefügt, um dieses Problem zu veranschaulichen. – stephband

Verwandte Themen