2015-07-28 18 views
24

Moje tablicy jest coś takiego:grupowe pozycje tablicy przy użyciu obiektu

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

chcę przekonwertować to do:

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

Więc w zasadzie, grupa przez group.

Staram:

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

ja po prostu nie wiem, jak radzić sobie grupowanie podobnych wartościach grupowych.

+0

Czy próbowali jeszcze coś? Istnieje już wiele ściśle powiązanych pytań dotyczących SO. Zobacz [this] (http://stackoverflow.com/questions/30893667/group-by-json-array-using-jquery), [this] (http://stackoverflow.com/questions/12873228/javascript-group- by-array) i [this] (http://stackoverflow.com/questions/25676026/group-array-with-sub-array). –

+0

Mnóstwo błędów składniowych. Przed wysłaniem sprawdź swój kod. – 1983

Odpowiedz

21

Po pierwsze, w języku JavaScript generalnie nie jest dobrym pomysłem powtarzanie nad tablicami przy użyciu for ... in. Szczegółowe informacje można znaleźć na stronie Why is using "for...in" with array iteration a bad idea?.

Więc możesz spróbować coś takiego:

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]}); 
} 

Korzystanie z pośrednictwa groups obiektu tutaj pomaga przyspieszyć rzeczy, ponieważ pozwala uniknąć zagnieżdżania pętli do przeszukiwania tablic. Ponadto, ponieważ groups jest obiektem (a nie tablicą), iteracja nad nim za pomocą for ... in jest właściwa.

Uzupełnienie

FWIW, jeśli chcesz uniknąć zduplikowane wpisy koloru w wyniku macierzy można dodać oświadczenie if powyżej linii groups[groupName].push(myArray[i].color); ustrzec się przed duplikatów. Używając jQuery wyglądałoby to tak;

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

Bez jQuery może chcesz dodać funkcję, która robi to samo co jQuery inArray:

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

a następnie używać go tak:

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

pamiętać, że zarówno Przypadek, który spowolni trochę z powodu całej iteracji, więc jeśli nie musisz unikać duplikatów kolorów w tablicach wyników, polecam unikanie tej dodatkowej współpracy. de. Nie

+1

Przykro mi, ale to nie działa, jeśli masz dwa takie same obiekty w '_myArray_. Z var myArray = [ {grupa: "jeden", kolor: "czerwony"}, {grupa: "dwa", kolor: "niebieski"}, {grupa: "jeden", kolor: "zielony"} , {grupa: "jeden", kolor: "czarny"}, {grupa: "jeden", kolor: "czarny"} ]; ' Otrzymasz' myArray [0] .color = ["czerwony "," zielony "," czarny "," czarny "]' – Lends

+0

"Nie działa" jest subiektywne. OP nigdy nie stwierdził, co należy zrobić w tej sprawie. – Jan

+0

@ Założeń OP nigdy nie określono jako wymaganie. W rzeczywistości, biorąc pod uwagę komentarz z PO, powiedziałbym, że to rozwiązanie rzeczywiście "działa". – neuronaut

4

Jedną z opcji jest:

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

Bardzo elegancki i samodzielny, miły. Moim jedynym problemem jest to, że nie jest tak odczytywalny jak prostsza pętla 'for'. – Jan

+1

zmniejszyć, indexOf, mapę, filtr, mapa wydaje się zbyt skomplikowane dla mnie. – 1983

+0

@KingMob Zdefiniuj "kompleks". Są to regularne metody tablicowe. – undefined

2

Ta wersja wykorzystuje ten przedmiot klucze są unikatowe. Przetwarzamy oryginalną tablicę i zbieramy kolory według grup w nowym obiekcie. Następnie utwórz nowe obiekty z tej grupy -> mapa tablic kolorów.

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] 
     }); 
    } 

Należy pamiętać, że nie bierze pod uwagę duplikatów barwach tej samej grupy, więc możliwe jest, aby mieć wielokrotność tego samego koloru w tablicy dla jednej grupy.

0

można zrobić coś takiego:

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

zacząć od stworzenia mapowanie nazw grup do wartości. Następnie przekształć w żądany format.

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);

Korzystanie instancji Array metody takie jak reduce i map daje potężne konstrukcje wyższego poziomu, że można zaoszczędzić dużo bólu zapętlenie ręcznie.

+2

Działa jak urok, dziękuję. –

+0

Świetna odpowiedź. Z Object.entries i ES6 możemy również wykonywać 'groups = Object.entries (group_to_values) .map (([grupa, kolor]) => ({grupa, kolor}));' – a15n

+0

Awesome! moim problemem było ciągnięcie kluczy, aby utworzyć tablicę obiektów za pomocą "Object.keys" – William

4

Przymież lodash w groupby sposób

Tworzy obiekt złożony z przycisków wytworzonych z wyników działania każdego elementu odbioru thru iteratee. Kolejność zgrupowanych wartości określa kolejność, w jakiej występują w kolekcji. Odpowiednia wartość każdego klucza jest tablicą elementów odpowiedzialnych za generowanie klucza. Iteratee wywoływane jest za pomocą jednego argumentu: (value).

Dzięki temu możesz dostać to, co chcesz, w jednej linii. Zobacz poniżej

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

Obok podanych podejść z dwóch podejścia towarzysza, można wziąć jeden podejście pętli przesuwając grupę jeśli nowa grupa zostanie znaleziony.

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)) 
} 
Powiązane problemy