2013-07-25 16 views
5

Sto usando JavaScript. Ho un array che contiene i dati in questo formato:Come posso raggruppare una matrice di oggetti per mese?

[ 
     {"USER_NAME":"User1","LAST_SUCCESSFUL_CONNECT":"1373978337642"}, 
     {"USER_NAME":"User2","LAST_SUCCESSFUL_CONNECT":"1374515704026"}, 
     {"USER_NAME":"User3","LAST_SUCCESSFUL_CONNECT":"1374749782479"} 
] 

(i numeri sopra rappresentano la data UTC/tempo in millisecondi

Vorrei gruppo (contare) i dati per mese qualcosa di simile.. :

[ 
    {"Month":"January, 2014","User_Count": 2}, 
    {"Month":"February, 2014","User_Count": 1}, 
] 

potevo usare jQuery se semplifica le cose

+2

Questo oggetto viene restituito da un server? In tal caso, consiglierei di restituire i dati nel formato corretto al client, invece di aggiungere la logica di analisi nello script java. In genere è più semplice e più unità testabile per eseguire questo tipo di logica sul server. – TGH

+0

Sì, sto recuperando i dati da un server in [oData] (http://www.odata.org/). Ciò significa che potrei anche non dover cambiare il codice del server, ma piuttosto usare l'opzione '$ count' di OData (non sono sicuro che questo mi darebbe quello che voglio). Tuttavia, ho già i dati grezzi nel client da una query precedente e vorrei salvare il round-trip. – Perspectivus

+0

Si prega di contrassegnare questa domanda come risposta se la mia risposta di seguito è effettivamente soddisfacente. Altrimenti, elaborato. – pygeek

risposta

10

Questo appare come un problema mapreduce. La soluzione di alto livello è la seguente:

  1. Riorganizzare i membri della lista.
  2. Contali.

Ecco un passo-passo come fare per raggiungere questo:

Mappa

  1. scorrere l'elenco dei dizionari
  2. Converti stringa di datetime a JavaScript oggetto datetime .
  3. Utilizzare mese-anno come chiave e elenco di dizionari come valore.

Questi sono ora raggruppati per mese-anno.

Esempio:

var l = [...]; 
var o = {}; 
var f = function(x){ 
    var dt_object = Date(x["LAST_SUCCESSFUL_CONNECT"]); // convert to datetime object 
    var key = dt_object.year + '-' + dt_object.month; 

    if (o[key] === undefined) { 
     var o[key] = []; 
    }; 

    o[key].push(x) 
} 

_.map(l, f(x)) //apply f to each member of l 

Ridurre

  1. Scorrere il nuovo oggetto che contiene dizionari di liste.
  2. Calcolare la lunghezza dell'elenco di ciascun dizionario.
  3. Utilizzare count come chiave e lunghezza dell'elenco come valore.

Esempio:

var g = function(member_count){ 
    //extra logic may go here 
    return member_count 
} 

for member in o { 
    count = _.reduce(l, g(member)) 
    member['count'] = count 
} 

risultante API

o['month-year'] //for list of dictionaries in that month 
o['month-year']['count'] //for the count of list of dictionaries in that month. 

Riferimenti:

Per map e reduce fu nctions in javascript vedono underscore.js:
http://underscorejs.org/#map
http://underscorejs.org/#reduce

Javascript Data oggetto:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

Per ulteriori informazioni sulla data e DateTime oggetti:
https://en.wikipedia.org/wiki/ISO_8601

Per maggiori informazioni su mapreduce:
https://en.wikipedia.org/wiki/MapReduce

+0

Grazie a @pygeek per la tua risposta elaborata. Non posso usare fonti open source o di terze parti diverse da jQuery, quindi underscorejs è pronto per me. Userò la mappa di jQuery e l'array di JavaScript ridurrà. – Perspectivus

1

Utilizzare Riduci mappa. Ecco un esempio che utilizza underscore.js. È molto semplice anche se è un po 'prolisso.

var data = [{ 
    "USER_NAME": "User1", 
     "LAST_SUCCESSFUL_CONNECT": "1373978337642" 
}, { 
    "USER_NAME": "User2", 
     "LAST_SUCCESSFUL_CONNECT": "1374515704026" 
}, { 
    "USER_NAME": "User3", 
     "LAST_SUCCESSFUL_CONNECT": "1374749782479" 
}, { 
    "USER_NAME": "User4", 
     "LAST_SUCCESSFUL_CONNECT": "1274749702479" 
}]; 

var monthNames = ["January", "February", "March", "April", "May", "June", 
    "July", "August", "September", "October", "November", "December"]; 

var map_result = _.map(data, function (item) { 
    var d = new Date(new Number(item.LAST_SUCCESSFUL_CONNECT)); 
    var month = monthNames[d.getMonth()] + ", " + d.getFullYear(); 
    return { 
     "Month": month, 
     "User_Count": 1 
    }; 
}); 

var result_temp = _.reduce(map_result, function (memo, item) { 
    if (memo[item.Month] === undefined) { 
     memo[item.Month] = item.User_Count; 
    }else{ 
     memo[item.Month] += item.User_Count; 
    } 
    return memo; 
},{}); 

//then wrap the result to the format you expected. 
var result = _.map(result_temp, function(value, key){ 
    return { 
     "Month": key, 
     "User_Count": value 
    }; 
}); 

console.log(result);