2012-07-31 20 views
5

¡He pasado toda la mañana jugando con esto ahora y leyendo aquí, pero me he encontrado dando vueltas en círculos!Combinación de matrices JSON con jQuery

Estoy tratando de dibujar un cuadro utilizando los excelentes gráficos de Javascript AmCharts, para mostrarme la tenencia de acciones como un gráfico de barras y stock como un gráfico de líneas.

No puedo obtener ambos conjuntos de datos de una consulta en mi base de datos, y no puedo usar AmCharts StockChart ya que no son datos basados ​​en tiempo ... por lo tanto, tengo dos conjuntos de datos que necesitan combinarse con Javascript.

Los datos se está tirando de una base de datos y devuelve correctamente como matrices JSON similares a esta:

VENTAS DE DATOS:

[{"brandName":"Fender","gearShiftedPerMonth":"35","retailSalesPerMonth":"55"}, 
{"brandName":"Gibson","gearShiftedPerMonth":"23","retailSalesPerMonth":"43"}, 
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13"}] 

datos de saldos:

[{"brandName":"Gibson","stockValue":"1234"}, 
{"brandName":"Fender","stockValue":"975"}, 
{"brandName":"Epiphone","stockValue":"834"}] 

¡Obviamente, las cifras reales están formadas en ese ejemplo!

Ahora, lo que tengo que hacer es combinar los para crear esta:

combinaron los datos

[{"brandName":"Fender","gearShiftedPerMonth":"35","retailSalesPerMonth":"55","stockValue":"975"}, 
{"brandName":"Gibson","gearShiftedPerMonth":"23","retailSalesPerMonth":"43","stockValue":"1234"}, 
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13","stockValue":"834"}] 

Lo que tenemos no es el conjunto de datos de ventas combina con la del conjunto de datos para agregar la adicional datos de stockValue agregados al registro de nombre de marca correspondiente.

He intentado usar $.extend pero no puedo encontrar la manera de usarlo en esta situación.

Quizás sea importante tener en cuenta que los pares de datos pueden no estar necesariamente en el orden correcto, y es posible, aunque poco probable, que no coincida, por lo que debe implementarse algún tipo de captura de error de puesta a cero.

+0

¿Por qué no se puede obtener ambos conjuntos de datos de una consulta? –

Respuesta

2

Creo que lo que él está tratando de hacer es unirse a los dos conjuntos de datos como si fueran tablas, uniéndose por el nombre de marca. Según lo que he estado probando, la función $ .extend() de jQuery no se ocupa de eso, sino que fusiona los objetos según su índice en las matrices de objetos que recibe.

Creo que la coincidencia de la clave tendría que hacerse manualmente.

stock = [{"brandName":"Fender","gearShiftedPerMonth":"35","retailSalesPerMonth":"55"}, 
{"brandName":"Gibson","gearShiftedPerMonth":"23","retailSalesPerMonth":"43"}, 
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13"}]; 
value = [{"brandName":"Gibson","stockValue":"1234"}, 
{"brandName":"Fender","stockValue":"975"}, 
{"brandName":"Epiphone","stockValue":"834"}]; 

var results = []; 
$(stock).each(function(){ 
    datum1 = this; 
    $(value).each(function() { 
     datum2 = this; 
     if(datum1.brandName == datum2.brandName) 
      results.push($.extend({}, datum1, datum2)); 
    }); 
}); 

lo que resultaría en:

[{"brandName":"Fender","gearShiftedPerMonth":"35","retailSalesPerMonth":"55","stockValue":"975"}, 
{"brandName":"Gibson","gearShiftedPerMonth":"23","retailSalesPerMonth":"43","stockValue":"1234"}, 
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13","stockValue":"834"}] 

En lugar de lo que el uso de $.extend() devuelve:

[{"brandName":"Gibson","gearShiftedPerMonth":"35","retailSalesPerMonth":"55","stockValue":"1234"}, 
{"brandName":"Fender","gearShiftedPerMonth":"23","retailSalesPerMonth":"43","stockValue":"975"}, 
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13","stockValue":"834"}] 
+0

Esto es correcto. Sin embargo, vea mi respuesta a continuación para un enfoque ligeramente diferente que sería más eficiente para conjuntos de datos muy grandes a expensas de la memoria. –

4

Lo que tendrá que hacer primero es transformar los datos en dos objetos, cuyas propiedades son los valores que desea combinar entre sí:

{ 
"Fender" : {"gearShiftedPerMonth":"35","retailSalesPerMonth":"55"}, 
"Gibson" : {"gearShiftedPerMonth":"23","retailSalesPerMonth":"43"}, 
"Epiphone" : {"gearShiftedPerMonth":"10","retailSalesPerMonth":"13"} 
} 

y

{ 
"Gibson": {"stockValue":"1234"}, 
"Fender": { "stockValue":"975"}, 
"Epiphone": { "stockValue":"834"} 
} 

Una vez que la transformación es hecho, tendrá dos objetos que puede fusionar usando $.extend u otras funciones.

actualización

Para los conjuntos grandes, esto da resultados en tiempo casi lineal:

var salesa = {}, stocka = {}; 
$.each(sales, function(i, e) { 
    salesa[e.brandName] = e; 
}); 
$.each(stock, function(i, e) { 
    stocka[e.brandName] = e; 
}); 

var combine = {}; 
$.extend(true, combine, salesa, stocka) 

Más velocidad puede ser ajustado si la fusión ocurrió durante la devolución de llamada segunda transformación ($each(stock...) en lugar de una llame por separado al $.extend() pero pierde algo de su obviedad.

+0

No es necesario transformar los datos de una matriz. – jholloman

+0

@jholloman: La transformación de los datos asegurará que los datos entre las marcas coincidan. Tenga en cuenta que en la pregunta, las marcas no se alinean consistentemente con los índices de matriz. +1 –

+0

Lamento haber asumido erróneamente que la solución extendida era correcta. ¿Qué propones como la forma más eficiente de transformar un objeto? – jholloman

1

En vainilla javascript que puede hacer:

var sales = [{"brandName":"Fender","gearShiftedPerMonth":"35","retailSalesPerMonth":"55"}, 
{"brandName":"Gibson","gearShiftedPerMonth":"23","retailSalesPerMonth":"43"}, 
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13"}]; 

var stock = [{"brandName":"Gibson","stockValue":"1234"}, 
{"brandName":"Fender","stockValue":"975"}, 
{"brandName":"Epiphone","stockValue":"834"}]; 

var combined = stock.slice(0);  

for (var i = 0; i < stock.length; i++) { 
    for (var j = 0; j < sales.length; j++) { 
     if (stock[i].brandName === sales[j].brandName) { 
      for (var attrname in sales[j]) { combined[i][attrname] = sales[j][attrname]; } 
     } 
    } 
} 

JSON.stringify(combined) 

produce

[ 
{"brandName":"Gibson","stockValue":"1234","gearShiftedPerMonth":"23","retailSalesPerMonth":"43"}, 
{"brandName":"Fender","stockValue":"975","gearShiftedPerMonth":"35","retailSalesPerMonth":"55"}, 
{"brandName":"Epiphone","stockValue":"834","gearShiftedPerMonth":"10","retailSalesPerMonth":"13"} 
] 
2

Si el código de ejemplo refleja la realidad, entonces jQuery de $.extend será la herramienta equivocadapara esto.

Copia ciegamente datos de un objeto a otro. Tenga en cuenta que el orden de sus datos no es coherente. Los DATOS DE VENTAS primero tienen Fender, mientras que los DATOS DE STOCK tienen primero gibson.

Así que jQuery's $.extend está mezclando los dos resultados. El "gearShifted" y "retailSales" para Fender terminan con "brandName" y "stockValue" para Gibson.


Lo que usted necesita es iterar una matriz, y buscar la "marca" en la otra, y luego copiar los datos que desea. Se podría utilizar $.extend para esa parte de ella si le gusta ...

var sales_data = 
[{"brandName":"Fender","gearShiftedPerMonth":"35","retailSalesPerMonth":"55"}, 
{"brandName":"Gibson","gearShiftedPerMonth":"23","retailSalesPerMonth":"43"}, 
{"brandName":"Epiphone","gearShiftedPerMonth":"10","retailSalesPerMonth":"13"}] 

var stock_data = 
[{"brandName":"Gibson","stockValue":"1234"}, 
{"brandName":"Fender","stockValue":"975"}, 
{"brandName":"Epiphone","stockValue":"834"}] 

var combined = $.map(sales_data, function(obj, i) { 

    return $.extend({}, obj, $.grep(stock_data, function(stock_obj) { 
     return obj.brandName === stock_obj.brandName 
    })[0]); 
}); 

Tenga en cuenta que esto no es muy eficiente, pero menos que el conjunto de datos es enorme, no debería ser un problema.


DEMO:http://jsfiddle.net/sDyKx/

RESULTADO:

[ 
    { 
     "brandName": "Fender", 
     "gearShiftedPerMonth": "35", 
     "retailSalesPerMonth": "55", 
     "stockValue": "975" 
    }, 
    { 
     "brandName": "Gibson", 
     "gearShiftedPerMonth": "23", 
     "retailSalesPerMonth": "43", 
     "stockValue": "1234" 
    }, 
    { 
     "brandName": "Epiphone", 
     "gearShiftedPerMonth": "10", 
     "retailSalesPerMonth": "13", 
     "stockValue": "834" 
    } 
] 
+0

Pensé que estaba equivocado, voté negativamente y borré mi respuesta para reducir el desorden. Debería haberme quedado con mis armas. –

+0

@clintp: Recupere su respuesta, y le daré +1. La suya es otra buena solución si los datos se pueden transformar. –

+0

Si * sabías * que había una relación 1: 1, podría ser más rápido ordenar las matrices por 'brandName' y luego fusionar desde allí. Las soluciones aquí son todas O (N * M) en el peor, y una clasificación podría ser tan baja como O (log N * log M). Es por eso que tomé un enfoque transformador al principio. –

Cuestiones relacionadas