2015-07-28 14 views
24

mia serie è qualcosa di simile:Gruppo elementi di matrice utilizzando oggetto

myArray = [ 
    {group: "one", color: "red"} 
    {group: "two", color: "blue"} 
    {group: "one", color: "green"} 
    {group: "one", color: "black"} 
] 

voglio convertire questo in:

myArray = [ 
    {group: "one", color: ["red", "green", "black"]} 
    {group: "two", color: ["blue"]} 
] 

Quindi, in sostanza, di gruppo per group.

Sto cercando:

for (i in myArray){ 
    var group = myArray[i].group; 
    //myArray.push(group, {???}) 
} 

io non so come gestire il raggruppamento di valori di gruppo simili.

+0

Hai provato ancora nulla? Ci sono già molte domande strettamente correlate su SO. Vedi [this] (http://stackoverflow.com/questions/30893667/group-by-json-array-using-jquery), [this] (http://stackoverflow.com/questions/12873228/javascript-group- by-array) e [this] (http://stackoverflow.com/questions/25676026/group-array-with-sub-array). –

+0

Un sacco di errori di sintassi lì. Si prega di testare il codice prima di postare. – 1983

risposta

21

Innanzitutto, in JavaScript non è generalmente una buona idea eseguire iterazioni sugli array utilizzando for ... in. Vedi Why is using "for...in" with array iteration a bad idea? per i dettagli.

Così si potrebbe provare qualcosa di simile:

var groups = {}; 
for (var i = 0; i < myArray.length; i++) { 
    var groupName = myArray[i].group; 
    if (!groups[groupName]) { 
    groups[groupName] = []; 
    } 
    groups[groupName].push(myArray[i].color); 
} 
myArray = []; 
for (var groupName in groups) { 
    myArray.push({group: groupName, color: groups[groupName]}); 
} 

Utilizzando la groups oggetto intermediario qui aiuta ad accelerare perché permette di evitare la nidificazione loop per la ricerca in array. Inoltre, poiché groups è un oggetto (piuttosto che un array) che iterating su di esso utilizzando for ... in è appropriato.

Addendum

FWIW, se si vuole evitare voci duplicate colore nelle matrici risultanti si potrebbe aggiungere un if dichiarazione di cui sopra la linea groups[groupName].push(myArray[i].color); in guardia contro i duplicati. Usando jQuery sembrerebbe questo;

if (!$.inArray(myArray[i].color, groups[groupName])) { 
    groups[groupName].push(myArray[i].color); 
} 

Senza jQuery si può decidere di aggiungere una funzione che fa la stessa cosa come inArray di jQuery:

Array.prototype.contains = function(value) { 
    for (var i = 0; i < this.length; i++) { 
    if (this[i] === value) 
     return true; 
    } 
    return false; 
} 

e quindi utilizzarlo in questo modo:

if (!groups[groupName].contains(myArray[i].color)) { 
    groups[groupName].push(myArray[i].color); 
} 

Si noti che in entrambi i caso si rallenterà un po 'a causa di tutte le iterazioni aggiuntive, quindi se non è necessario evitare voci di colore duplicate negli array di risultati, consiglierei di evitare questo extra de. Ci

+1

Mi dispiace ma non funziona se si hanno due stessi oggetti in '_myArray_. con var myArray = [ {gruppo: "uno", colore: "rosso"}, {gruppo: "due", colore: "blu"}, {gruppo: "uno", colore: "verde"} , {group: "one", colour: "black"}, {group: "one", colour: "black"} ]; ' Otterrai' myArray [0] .color = ["rosso "," verde "," nero "," nero "]' – Lends

+0

"Non funziona" è soggettivo. OP non ha mai detto cosa fare in quel caso. – Jan

+0

@Lends l'OP non l'ha mai specificato come requisito. Infatti, dato il commento dall'OP, direi che questa soluzione funziona davvero ". – neuronaut

4

Una possibilità è:

var res = myArray.reduce(function(groups, currentValue) { 
    if (groups.indexOf(currentValue.group) === -1) { 
     groups.push(currentValue.group); 
    } 
    return groups; 
}, []).map(function(group) { 
    return { 
     group: group, 
     color: myArray.filter(function(_el) { 
      return _el.group === group; 
     }).map(function(_el) { return _el.color; }) 
    } 
}); 

http://jsfiddle.net/dvgwodxq/

+3

Molto elegante e autonomo, bello. La mia unica lamentela è che non è immediatamente leggibile come un semplice 'for' loop. – Jan

+1

ridurre, indexOf, map, filter, map mi sembra troppo complesso. – 1983

+0

@KingMob Definire "complesso". Quelli sono metodi standard dell'array. – undefined

2

Questa versione sfrutta quell'oggetto chiavi sono uniche. Elaboriamo la matrice originale e raccogliamo i colori per gruppo in un nuovo oggetto. Quindi crea nuovi oggetti da quel gruppo -> mappa array di colori.

var myArray = [{ 
     group: "one", 
     color: "red" 
    }, { 
     group: "two", 
     color: "blue" 
    }, { 
     group: "one", 
     color: "green" 
    }, { 
     group: "one", 
     color: "black" 
    }]; 

    //new object with keys as group and 
    //color array as value 
    var newArray = {}; 

    //iterate through each element of array 
    myArray.forEach(function(val) { 
     var curr = newArray[val.group] 

     //if array key doesnt exist, init with empty array 
     if (!curr) { 
     newArray[val.group] = []; 
     } 

     //append color to this key 
     newArray[val.group].push(val.color); 
    }); 

    //remove elements from previous array 
    myArray.length = 0; 

    //replace elements with new objects made of 
    //key value pairs from our created object 
    for (var key in newArray) { 
     myArray.push({ 
     'group': key, 
     'color': newArray[key] 
     }); 
    } 

Si prega di notare che questo non tiene conto colori duplicati dello stesso gruppo, per cui è possibile avere più dello stesso colore nella matrice per un singolo gruppo.

0

si può fare qualcosa di simile:

function convert(items) { 
    var result = []; 

    items.forEach(function (element) { 
     var existingElement = result.filter(function (item) { 
      return item.group === element.group; 
     })[0]; 

     if (existingElement) { 
      existingElement.color.push(element.color); 
     } else { 
      element.color = [element.color]; 
      result.push(element); 
     } 

    }); 

    return result; 
} 
35

Inizia con la creazione di una mappatura dei nomi dei gruppi per i valori. Quindi trasformare nel formato desiderato.

var myArray = [ 
 
    {group: "one", color: "red"}, 
 
    {group: "two", color: "blue"}, 
 
    {group: "one", color: "green"}, 
 
    {group: "one", color: "black"} 
 
]; 
 

 
var group_to_values = myArray.reduce(function (obj, item) { 
 
    obj[item.group] = obj[item.group] || []; 
 
    obj[item.group].push(item.color); 
 
    return obj; 
 
}, {}); 
 

 
var groups = Object.keys(group_to_values).map(function (key) { 
 
    return {group: key, color: group_to_values[key]}; 
 
}); 
 

 
var pre = document.createElement("pre"); 
 
pre.innerHTML = "groups:\n\n" + JSON.stringify(groups, null, 4); 
 
document.body.appendChild(pre);

Utilizzando metodi di istanza Array quali reduce e map ti dà potenti costrutti di livello superiore che possono risparmiare un sacco di dolore di loop manualmente.

+2

Funziona come un incantesimo, grazie. –

+0

Ottima risposta. Con Object.entries ed ES6 possiamo anche fare 'groups = Object.entries (group_to_values) .map (([group, color]) => ({group, color}))' – a15n

+0

Awesome! il mio problema era tirare le chiavi per formare una serie di oggetti usando 'Object.keys' – William

4

groupby metodo Utilizzo lodash

Crea un oggetto composto di chiavi generate dai risultati di esecuzione di ciascun elemento di raccolta attraverso iteratee. L'ordine dei valori raggruppati è determinato dall'ordine in cui si verificano nella raccolta. Il valore corrispondente di ogni chiave è una matrice di elementi responsabili della generazione della chiave. L'iteratee viene invocato con un argomento: (valore).

Quindi con lodash è possibile ottenere ciò che si desidera in una singola riga. Vedi sotto

let myArray = [ 
 
    {group: "one", color: "red"}, 
 
    {group: "two", color: "blue"}, 
 
    {group: "one", color: "green"}, 
 
    {group: "one", color: "black"}, 
 
] 
 
let grouppedArray=_.groupBy(myArray,'group') 
 
console.log(grouppedArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

1

Oltre gli approcci dato con un approccio a due passaggi, si potrebbe prendere un approccio unico ciclo spingendo il gruppo se viene trovato un nuovo gruppo.

var array = [{ group: "one", color: "red" }, { group: "two", color: "blue" }, { group: "one", color: "green" }, { group: "one", color: "black" }], 
 
    groups = Object.create(null), 
 
    grouped = []; 
 

 
array.forEach(function (o) { 
 
    if (!groups[o.group]) { 
 
     groups[o.group] = []; 
 
     grouped.push({ group: o.group, color: groups[o.group] }); 
 
    } 
 
    groups[o.group].push(o.color); 
 
}); 
 

 
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

-1
var array = [{ 
     id: "123", 
     name: "aaaaaaaa" 
    }, { 
     id: "123", 
     name: "aaaaaaaa" 
    }, { 
     id: '456', 
     name: 'bbbbbbbbbb' 
    }, { 
     id: '789', 
     name: 'ccccccccc' 
    }, { 
     id: '789', 
     name: 'ccccccccc' 
    }, { 
     id: '098', 
     name: 'dddddddddddd' 
    }]; 
//if you want to group this array 
group(array, key) { 
    console.log(array); 
    let finalArray = []; 
    array.forEach(function(element) { 
    var newArray = []; 
    array.forEach(function(element1) { 
     if (element[key] == element1[key]) { 
      newArray.push(element) 
     } 
    }); 
    if (!(finalArray.some(arrVal => newArray[0][key] == arrVal[0][key]))) { 
     finalArray.push(newArray); 
    } 
    }); 
    return finalArray 
} 
//and call this function 
groupArray(arr, key) { 
    console.log(this.group(arr, key)) 
} 
Problemi correlati