json - GroupByWithSumPipe för att sortera en lista och summera ett attribut för grupperade objekt Angular


Jag använder en GroupBy-pipeline för att gruppera mina data enligt en parameter och det fungerar mycket bra, men jag skulle vilja lägga till en andra parameter till denna pipeline på följande sätt:

<li *ngFor="let object of myArray | groupByWithSum:'color':'price'">
    COLOR:{{object.key}} - SUM_PRICE:{{object.sum}}
</li>

Tillåter summan av alla objekt grupperade enligt ett objekts attribut, här price.

Exempel: StackBlitz HÄR

Här är min objektlista:

var myArray = [
    { name: "Apple",    color: "Green",     price: "5,999" },
    { name: "Banana",   color: "Yellow",    price: "6,999" },
    { name: "Grape",    color: "Green",     price: "12,999" },
    { name: "Melon",    color: "Yellow",    price: "10,999" },
    { name: "Orange",   color: "Orange",    price: "3,999" }
];

Jag vill sortera den här listan efter färg och få den totala summan av priser efter färg.

Och det är vad jag skulle vilja få:

[
    {
        key: "Green",
        sum: "18,998‬",
        value: [
            { name: "Apple", color: "Green", price: "5,999" },
            { name: "Grape", color: "Green", price: "12,999" }
        ]
    },
    {
        key: "Yellow",
        sum: "17,998",
        value: [
            { name: "Banana", color: "Yellow", price: "6,999" },
            { name: "Melon",  color: "Yellow", price: "10,999" }
        ]
    },
    {
        key: "Orange",
        sum: "3,999",
        value: [
            { name: "Orange", color: "Orange", price: "3,999" }
        ]
    }
];

Jag startade en StackBlitz som sorterar listan efter color, men jag kan inte få summan. Om någon skulle vara villig att hjälpa mig.

GroupByWithSumPipe:

export class GroupByWithSumPipe implements PipeTransform {
  transform(collection: object[], property: string, sum: string): object[] {
    // prevents the application from breaking if the array of objects doesn't exist yet
    if(!collection) { return null; }

    const groupedCollection = collection.reduce((previous, current)=> {
      if(!previous[current[property]]) {
          previous[current[property]] = [current];
      } else {
          previous[current[property]].push(current);
      }

      return previous;
    }, {});

    // this will return an array of objects, each object containing a group of objects
    return Object.keys(groupedCollection).map(key => ({ key, value: groupedCollection[key] }));
  }
}

Tack på förhand.

Svar #1

På din return-sats kan du lägga till summasatsen:

transform(collection: object[], property: string, sum: string): object[] {
  //...

  return Object.keys(groupedCollection).map(key => ({ 
    key, 
    sum: groupedCollection[key].reduce((a, b) => a + parseInt(b[sum]), 0),
    value: groupedCollection[key]
  }));
}

exempel

Du använder strängar för priset dock, jag har lagt till en parseInt för att få det att fungera men det är bättre om du bara gör dessa värden till nummer i din källdata