2013-04-08 19 views
23

Jak przekonwertować to:obiektów grupa posesją w javascript

[ 
    {food: 'apple', type: 'fruit'}, 
    {food: 'potato', type: 'vegetable'}, 
    {food: 'banana', type: 'fruit'}, 
] 

w tym:

[ 
    {type: 'fruit', foods: ['apple', 'banana']}, 
    {type: 'vegetable', foods: ['potato']} 
] 

użyciu JavaScript lub podkreślenia

+2

@Harley Najlepiej pokazać to, czego próbowaliśmy . Zwięzłe nie jest tak ważne, jak pokazanie wysiłku. Nie jest to również zwykła prośba - zobaczenie, gdzie jesteś, daje nam lepsze ujęcie w tworzeniu czegoś dokładnie na wymaganym poziomie. – ErikE

+1

OK, przepraszam za to. –

+1

@ErikE Alternatywnie, jest to ładne i proste pytanie, które ma wysoką łatwość zapisu, bez takich bzdur, jak nieudane i zawiłe próby rozwiązania. To jest pytanie, które uzyska najwięcej głosów uprzywilejowanych, ponieważ generyczny i odpowiedź będą również korzystne, ostatecznie przynosząc korzyść wszystkim. –

Odpowiedz

78

Zakładając oryginalny wykaz jest zawarty w zmienna o nazwie list:

_ 
.chain(list) 
.groupBy('type') 
.map(function(value, key) { 
    return { 
     type: key, 
     foods: _.pluck(value, 'food') 
    } 
}) 
.value(); 
+3

Wow, to jest zwięzłe! – ErikE

+0

To jest naprawdę wspaniałe - dzięki! –

+0

@ErikE Udział w kodzie golfowym ma swoje zalety :) – Anurag

17

Bez użycia podkreślenia:

var origArr = [ 
    {food: 'apple', type: 'fruit'}, 
    {food: 'potato', type: 'vegetable'}, 
    {food: 'banana', type: 'fruit'} 
]; 

/*[ 
    {type: 'fruit', foods: ['apple', 'banana']}, 
    {type: 'vegetable', foods: ['potato']} 
]*/ 

function transformArr(orig) { 
    var newArr = [], 
     types = {}, 
     i, j, cur; 
    for (i = 0, j = orig.length; i < j; i++) { 
     cur = orig[i]; 
     if (!(cur.type in types)) { 
      types[cur.type] = {type: cur.type, foods: []}; 
      newArr.push(types[cur.type]); 
     } 
     types[cur.type].foods.push(cur.food); 
    } 
    return newArr; 
} 

console.log(transformArr(origArr)); 

DEMO:http://jsfiddle.net/ErikE/nSLua/3/

zasługa @ErikE na poprawę/zmniejszenie mój oryginalny kod, aby pomóc z redundancją miałem :)

+0

Sugestia: wstaw 'newArr.push (types [cur.type]);' wewnątrz twojego bloku 'if' i całkowicie usuń drugą pętlę' for'. – ErikE

+0

@ErikE Tak, już refaktoryzuję. Wiem, że podwójna pętla nie jest dobra, więc wróciłem. Trzymaj się, może to, co robię, jest tym, co mówisz. – Ian

+0

@ErikE Myślę, że zajęło mi to trochę więcej niż sugerowałeś, ale już zapomniałem, jak kiedyś wyglądało. Wygląda na to, że działa i nie wymaga 2 pętli, więc wygląda na to, że jest w porządku :) – Ian

3
var foods = [ 
    {food: 'apple', type: 'fruit'}, 
    {food: 'potato', type: 'vegetable'}, 
    {food: 'banana', type: 'fruit'} 
]; 

var newFoods = _.chain(foods).reduce(function(memo, food) { 
    memo[ food.type ] = memo[ food.type ] || []; 
    memo[ food.type ].push(food.food); 
    return memo; 
}, {}).map(function(foods, type) { 
    return { 
     type: type, 
     foods: foods 
    }; 
}).value(); 

http://jsbin.com/etaxih/2/edit

0

Możesz grupować tablice obiektów według jednego z pól z biblioteką Alasql. Ten przykład kompaktowe tablice dokładnie tak, jak w przykładzie:

var res = alasql('SELECT type, ARRAY(food) AS foods FROM ? GROUP BY type',[food]); 

wypróbować ten przykład at jsFiddle.

6

Tu jest nieco inna, ale bardziej ogólny wersja @ odpowiedź Iana

Zastrzeżenie: wynik jest nieco inny od wymogu PO, ale inni, jak ja, którzy potykają się na to pytanie może korzystać z bardziej rodzajowy oDPOWIEDŹ IMHO

var origArr = [ 
    {food: 'apple', type: 'fruit'}, 
    {food: 'potato', type: 'vegetable'}, 
    {food: 'banana', type: 'fruit'} 
]; 

function groupBy(arr, key) { 
     var newArr = [], 
      types = {}, 
      newItem, i, j, cur; 
     for (i = 0, j = arr.length; i < j; i++) { 
      cur = arr[i]; 
      if (!(cur[key] in types)) { 
       types[cur[key]] = { type: cur[key], data: [] }; 
       newArr.push(types[cur[key]]); 
      } 
      types[cur[key]].data.push(cur); 
     } 
     return newArr; 
} 

console.log(groupBy(origArr, 'type')); 

można znaleźć jsfiddle here

+0

Cześć. Właśnie tego szukam! Dziękuję Ci! - Myślę, że dobrze byłoby pokazać, co 'console.log' wypisuje. – onebree

+0

Niewykorzystana zmienna newItem i j. Czemu? – maXp

1

ES6 rozwiązanie tego stare pytanie:

Powtórz iterację za pomocą Array#reduce i odbierz elementy według grup do numeru Map. Użyj spread do konwersji Map#values powrotem do tablicy:

const data = [ 
 
    {food: 'apple', type: 'fruit'}, 
 
    {food: 'potato', type: 'vegetable'}, 
 
    {food: 'banana', type: 'fruit'}, 
 
]; 
 

 
const result = [...data.reduce((hash, { food, type }) => { 
 
    const current = hash.get(type) || { type, foods: [] }; 
 
    
 
    current.foods.push({ food }); 
 
    
 
    return hash.set(type, current); 
 
}, new Map).values()]; 
 

 
console.log(result);

0

Można również korzystać z innych funkcji, takich jak ES6:

function groupArray(arr, groupBy, keepProperty) { 
     let rArr = [], i; 
     arr.forEach(item => { 
      if((i = rArr.findIndex(obj => obj[groupBy] === item[groupBy])) !== -1) 
       rArr[i][`${keepProperty}s`].push(item[keepProperty]); 
      else rArr.push({ 
       [groupBy]: item[groupBy], 
       [`${keepProperty}s`]: [item[keepProperty]] 
      }); 
     }); 
     return rArr; 
    } 

    groupArray(yourArray, 'type', 'food'); 
Powiązane problemy