【问题标题】:Angular check matching objects in two arrays, TypeScript best way角度检查两个数组中的匹配对象,TypeScript 最好的方法
【发布时间】:2018-03-30 01:11:02
【问题描述】:

我遇到了一个问题,我无法在 TypeScript 中解决它。我正在使用 Angular,此代码来自服务。我有这一系列的成分:

private ingredients: Ingredient[] = [
  new Ingredient('farina', 500),
  new Ingredient('burro', 80),
  new Ingredient('uccellini', 5)
];

这是型号:export class Ingredient {constructor(public name: string, public amount: number){}}

现在我想向数组中添加新成分,并使用新数组的副本发出一个事件:这可行:

newIngredients = [
  new Ingredient('mais', 100),
  new Ingredient('uccellini', 5)
];

addIngredients(newIngredients: Ingredient[]) {
  this.ingredients.push(...ingredients);
  this.ingredientsChanged.emit(this.ingredients.slice());
}

但是我想检查成分数组中是否存在新的成分对象,如果存在,将新旧数量值相加在一个对象中,并推送更新的对象,然后返回数组的副本.

预期输出:

[
  new Ingredient('farina', 500),
  new Ingredient('burro', 80),
  new Ingredient('uccellini', 10)
  new Ingredient('mais', 100)
];

我尝试过Set、WeakSet、Map等方式,但我对Typescript了解不多。这就是我卡住的地方:

addIngredients(newIngredients: Ingredient[]) {

  let hash = {};
  this.ingredients.forEach(function (ingr) {
    hash[ingr.name] = ingr;
  });

let result = newIngredients.filter(function (ingr) {
  if (!(ingr.name in hash)) {
    return !(ingr.name in hash);
  } else {
    // ???
  }
});

  this.ingredients.push(...result);
  this.ingredientsChanged.emit(this.ingredients.slice());
}

感谢您的帮助

【问题讨论】:

    标签: javascript arrays angular typescript object


    【解决方案1】:

    假设你有两个数组

    const ingredients: Ingredient[] = [
      new Ingredient('farina', 500),
      new Ingredient('burro', 80),
      new Ingredient('uccellini', 5)
    ];
    

    const newIngredients = [
      new Ingredient('mais', 100),
      new Ingredient('uccellini', 5)
    ];
    

    如果添加不存在的成分并组合存在的成分,您想将它们组合起来,

    你可以做的是合并两个数组,然后减少直到只有一个列表

    const combined = ingredients
      .concat(newIngredients)
      .reduce((prev: any[], curr: any) => {
        const temp = prev.filter(a => a.name === curr.name)
        if (temp.length > 0) {
          prev.push({ ...curr, value: temp.shift().value + curr.value })
        } else {
          prev.push(curr)
        }
        return prev
      }, [])
    

    【讨论】:

    • 对不起,但不起作用,combined 有一个新值,但不是成分类型,并且是一个带有{name: "uccellini", amount: 5, value: NaN} 的对象。但是,我认为 .concat().reduce() 的组合会有所帮助。谢谢
    • 我的代码只是你如何解决问题的一个例子,不是真实的数据,
    【解决方案2】:

    更新答案:

    1. 'this.ingredients' 在 forEach 中不可访问,因为该函数调用的上下文已更改

    2. 因此将 'this' 分配给 'that' 变量,这使得 'that.ingredients' 可以在 forEach 中访问

    StackBlitz 网址:https://stackblitz.com/edit/angular-fulrcg

    addIngredients(newIngredients: Ingredient[]) {
    
        let exist: boolean = false;
        let that = this;
        //debugger;
        console.log(this.ingredients);
        newIngredients.forEach(function(newIngr, newKey) {
          exist = false;
          console.log(newIngr);
          that.ingredients.forEach(function (ingr, key) {
            if(ingr["name"] == newIngr["name"]) {
              ingr["amount"] += newIngr["amount"];
              exist = true;
            }
          });
          if(!exist) {
            **that.ingredients**.push(newIngr);
          }
        });
    

    【讨论】:

    • PS:使用箭头函数我不需要定义that = this
    【解决方案3】:

    下面是sn-p的代码:

    Stackblitz 网址:https://stackblitz.com/edit/angular-uf4dcr

    app.component.html

    <button (click)="add()">Add</button>
    
    <ul>
      <li *ngFor="let ing of ingredients">
        {{ing.name}} - {{ing.amount}}
      </li>
    </ul>
    

    app.component.ts

    import { Component } from '@angular/core';
    
    class Ingredient {
      constructor(public name: string, public amount: number){ }
    }
    
    
    
    @Component({
      selector: 'my-app',
      templateUrl: './app.component.html',
      styleUrls: [ './app.component.css' ]
    })
    export class AppComponent  {
      name = 'Angular 5';
    
      private ingredients: Ingredient[] = [
        new Ingredient('farina', 500),
        new Ingredient('burro', 80),
        new Ingredient('uccellini', 5)
      ];
    
      addIngredients(newIngredients: Ingredient) {
    
        let exist: boolean = false;
        this.ingredients.forEach(function (ingr) {
          if(ingr["name"] == newIngredients["name"]) {
            ingr["amount"] += newIngredients["amount"];
            exist = true;
          }
        });
    
        if(!exist) {
          this.ingredients.push(newIngredients);
        }
    
          //this.ingredientsChanged.emit(this.ingredients.slice());
          console.log([...this.ingredients]); //return copy of the updated array
      }
    
      add() {
        this.addIngredients({name: 'farina', amount:10});
        this.addIngredients({name: 'new item', amount:100});
      }
    
    }
    

    【讨论】:

    • 对不起,如果传递一个成分类型的对象数组,则不起作用,仅当您传递单个对象时才起作用
    • 添加了新答案。问题是 forEach 中的上下文。在 forEach 中无法访问 this.ingredients。参考:stackoverflow.com/questions/15013016/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多