2012-05-09 14 views
14

Quando si utilizza Crossfilter (https://github.com/square/crossfilter), si specificano le funzioni da utilizzare quando si aggiungono e si rimuovono i dati da un gruppo. E 'abbastanza banale per tenere traccia di una media in esecuzione (utilizzando CoffeeScript):Utilizzando Crossfilter, è possibile tenere traccia di max/min durante il raggruppamento?

reduceAdd = (p, v) -> 
    ++p.count; 
    p.sum += v.digit; 
    p 

reduceRemove = (p, v) -> 
    --p.count; 
    p.sum -= v.digit; 
    p 

reduceInitial = -> 
    { 
    count: 0 
    sum: 0 
    average: -> 
     return 0 if this.count == 0 
     return this.sum/this.count 
    } 

E' possibile tenere traccia del massimo e minimo di ogni gruppo? Non riesco a capire un modo per non tenere tutti gli elementi in un enorme array e fare un d3.min/d3.max. Sembra che aggiungere/rimuovere dati sarebbe estremamente inefficiente.

Ho anche cercato un modo per dire a Crossfilter di ricostruire completamente il gruppo da zero, piuttosto che rimuovere elementi da un gruppo esistente. Se viene applicato un filtro, il gruppo viene ripristinato e ricostruito. Niente di ovvio.

+0

appena incontrato lo stesso problema. A proposito, ho aperto un problema in github, https://github.com/square/crossfilter/issues/25 – CambridgeMike

risposta

0

Dopo aver giocato un po 'con questo, è possibile ricostruire il gruppo richiamando nuovamente il metodo di gruppo.

+0

Interessante, lo verificherò.BTW, non potrei fare un tag 'crossfilter' in SO senza più reputazione. Se qualcuno si imbatte in questo e può creare un tag, sono felice di re-taggare la mia domanda. –

+1

Appena creato il tag. Speriamo che Crossfilter sia una grande libreria e che otterrà più attenzione. – Pablojim

+1

Puoi spiegare la soluzione in modo più dettagliato? Quando/come ricostruisci il gruppo? –

9

È possibile utilizzare dimension.top(1) e dimension.bottom(1) per recuperare il minimo e il massimo correnti. Questi metodi rispettano tutti i filtri che possono essere attivi sul filtro incrociato.

+1

Come useresti dimension.top e dimensione.bottom per ottenere il massimo e il minimo per gruppo? –

2

La soluzione migliore che ho trovato era quella di tenere traccia di tutti i valori in una lista ordinata e aggiungere elementi con una semplice funzione di inserimento in stile quicksort (vedere come insert a number into a sorted array) e rimuoverli usando indexOf.

funzioni comuni:

function insertElement(element, array) { 
    array.splice(locationOfElement(element, array) + 1, 0, element); 
    return array; 
} 

function removeElement(element, array) { 
    var index = array.indexOf(element); 
    if (index >= 0) array.splice(index, 1); 
    return array; 
} 

function locationOfElement(element, array, start, end) { 
    start = start || 0; 
    end = end || array.length; 
    var pivot = parseInt(start + (end - start)/2, 10); 
    if (array[pivot] === element) return pivot; 
    if (end - start <= 1) 
     return array[pivot] > element ? pivot - 1 : pivot; 
    if (array[pivot] < element) { 
     return locationOfElement(element, array, pivot, end); 
    } else { 
     return locationOfElement(element, array, start, pivot); 
    } 
} 

function maxElement(array) { 
    return (array.length > 0) ? 
     array[array.length - 1] : null; 
} 

function minElement(array) { 
    return (array.length > 0) ? 
     array[0] : null; 
} 

funzioni da utilizzare quando si aggiunta e la rimozione dei dati da un gruppo per tenere traccia min/max:

minMaxDimension = cf.dimension(function (d) { 
    return d.key; 
}); 

var reduceAdd = function(p, v) { 
    insertElement(v.value, p.elements); 
    return p; 
}; 

var reduceRemove = function(p, v) { 
    removeElement(v.value, p.elements); 
    return p; 
}; 

var reduceInitial = function() { 
    return { 
     elements: [], 
     max: function() { return maxElement(elements); }, 
     min: function() { return minElement(elements); } 
    } 
} 

minMaxGroup = minMaxDimension 
    .group() 
    .reduce(reduceAdd, reduceRemove, reduceInitial) 
    .orderNatural() 
    .top(Infinity); 
+0

questa è la soluzione più efficiente di gran lunga. – Gordon

+0

Penso che tu possa usare [d3.bisectRight] (https://github.com/mbostock/d3/wiki/Arrays#d3_bisectRight) invece di 'locationOfElement' – Gordon

Problemi correlati