为了账号安全,请及时绑定邮箱和手机立即绑定

删除对象项并将其添加到数组中,如果数组中已存在特定项,则更改对象键

删除对象项并将其添加到数组中,如果数组中已存在特定项,则更改对象键

炎炎设计 2023-03-24 15:39:38
我有这个食谱数组,其中每个对象都是一个特定的食谱,每个食谱都有一个成分数组,每个成分都是由_id name quantity. 如果你们知道为什么会这样,请在下面添加我的问题,请告诉我。我挣扎了 3 天......任何建议将不胜感激。多谢!(3) [{…}, {…}, {…}]0:ingredients: Array(4)0: {_id: "5f6628d0029e87e02c79ce0a", name: "chia", quantity: 10}1: {_id: "5f6628d0029e87e02c79ce0b", name: "apple", quantity: 15}2: {_id: "5f6628d0029e87e02c79ce0c", name: "honey", quantity: 30}3: {_id: "5f6628d0029e87e02c79ce0d", name: "almond flour", quantity: 35}length: 4__proto__: Array(0)name: "Coconut Chia Pudding"__v: 0_id: "5f6628d0029e87e02c79ce09"__proto__: Object1: {_id: "5f6628d0029e87e02c79ce0e", name: "Peanut Butter Cookies", ingredients: Array(4), __v: 0}2: {_id: "5f6628d0029e87e02c79ce13", name: "Caprese Avocado Bowls", ingredients: Array(3), __v: 0}length: 3__proto__: Array(0)我在 UI 中拥有的是一个包含上述食谱的列表,用户可以勾选和取消勾选,在勾选食谱后,其成分显示在列表中。HTML<ion-content>  <ion-grid>    <ion-row>      <ion-col>        <ion-list>          <ion-item            *ngFor="let recipe of loadedRecipes; let lastRecipe = last"            [ngClass]="{ 'last-recipe': lastRecipe }"          >            <ion-checkbox              (ionChange)="onCheckRecipe($event)"              value="{{recipe.name}}"            ></ion-checkbox>            <ion-label>{{recipe.name}}</ion-label>            <ion-button              [routerLink]="['/','recipes','recipe-details', recipe._id]"              >></ion-button            >          </ion-item>        </ion-list>      </ion-col>    </ion-row>    <ion-row>      <ion-col>        <h6 class="ion-padding-start" *ngIf="groceryList.length > 0">          Grocery List        </h6>        <ion-list *ngIf="groceryList.length > 0">          <ion-item *ngFor="let ingredient of groceryList">            <ion-label>{{ingredient.name}}</ion-label>            <ion-note slot="end">{{ingredient.quantity}} g</ion-note>          </ion-item>        </ion-list>      </ion-col>    </ion-row>  </ion-grid></ion-content>
查看完整描述

2 回答

?
慕村9548890

TA贡献1884条经验 获得超4个赞

问题在于您的 if 语句的流程。在代码的“onRemove”部分,您说的是“如果成分在列表中,则将其从列表中删除。如果不在,则减少其数量。” 第二部分没有任何意义,更重要的是,你永远也做不到,因为成分应该总是在列表中。


for (let eachIngredient of recipe.ingredients) {

  let matched = this.groceryList.find(function(foundIngre) {

    return foundIngre.name === eachIngredient.name;

  });

  if (

    matched.name === eachIngredient.name &&

    matched._id === eachIngredient._id

  ) {

    let index = this.groceryList.findIndex(

      (x) => x._id === matched._id

    );

    // Problem e ca eachIngredient.quantity se schimba

    this.groceryList.splice(index, 1);

  } else {

    matched.quantity = matched.quantity - eachIngredient.quantity;

  }

}

根据你所说的,你想要做的是:

  1. 减去归因于已删除配方的数量

  2. 如果新数量为零,则从列表中删除该成分(尽管您也可以保留它并忽略数量为零的成分)

试试这个:

for (let eachIngredient of recipe.ingredients) {

  // I am assuming that ids are unique so I am not checking foundIngre.name at all, 

  // since I assume that ingredients with the same name must also have the same name

  // I am also using findIndex first so that you don't need a second find when removing

  const matchIndex = this.groceryList.findIndex( 

     (foundIngre) => foundIngre._id === eachIngredient._id

  );

  if ( matchIndex ) { // this should always be true

    const matched = this.groceryList[matchIndex];

    // preserve the entry if there is still some quantity

    if ( matched.quantity > eachIngredient.quantity ) {

      matched.quantity = matched.quantity - eachIngredient.quantity; // can use -= to shorten

    }

    // remove from the list only if there is no quantity remaining

    else {

        this.groceryList.splice(matchIndex, 1);

    }

  }

}

编辑: 尝试更新和删除数组中的项目是一种不必要的痛苦。修改后的代码版本将 _groceryList 存储在键控字典中。我最初打算按成分 ID 键,但在查看您的演示后,我发现我的假设是错误的,即多个食谱中的相同成分将共享相同的 ID。所以我改为按成分名称键入。这样你就可以写入 _groceryList[name] 并且它以前是否存在并不重要。


该类有一个公共的 getter groceryList,它将私有的 _groceryList 字典转换为一个数组。


我还尝试通过使用一个通用toggleIngredient函数来消除场景分支中不必要的代码重复,该函数使用布尔值checked来控制它是通过乘以加号还是减号来控制加法或减法。


import { Component } from "@angular/core";

import { Platform } from "@ionic/angular";

import { SplashScreen } from "@ionic-native/splash-screen/ngx";

import { StatusBar } from "@ionic-native/status-bar/ngx";

import { Subscription } from "rxjs";


export interface Ingredient {

  _id: string;

  name: string;

  quantity: number;

}


export interface Recipe {

  _id: string;

  name: string;

  ingredients: Ingredient[];

}


@Component({

  selector: "app-root",

  templateUrl: "app.component.html"

})

export class AppComponent {


  private _recipesSub: Subscription;

  constructor(

    private platform: Platform,

    private splashScreen: SplashScreen,

    private statusBar: StatusBar,

  ) {

    this.initializeApp();

  }


  initializeApp() {

    this.platform.ready().then(() => {

      this.statusBar.styleDefault();

      this.splashScreen.hide();

    });

  }

  private loadedRecipes: Recipe[] = [/*...*/]


  // store the groceryList in a dictionary keyed by name

  private _groceryList: Record<string, Ingredient> = {};


  // getter returns the groceryList in array format, ignoring 0 quantities

  get groceryList(): Ingredient[] {

    return Object.values(this._groceryList).filter( ing => ing.quantity > 0 );

  }


  // get the current quantity for an ingredient by name, or 0 if not listed

  currentQuantity( name: string ): number {

    const ingredient = this._groceryList[name];

    return ingredient ? ingredient.quantity : 0;

  }


  // update the quantity for an ingredient when checked or unchecked

  // will add new ingredients, but never removes old ones

  toggleIngredient( ingredient: Ingredient, checked: boolean ): void {

    // add to or remove from quantity depending on the value of checked

    const quantity = this.currentQuantity(ingredient.name) + (checked ? 1 : -1 ) * ingredient.quantity;

    // replace the object in the grocery list dictionary

    this._groceryList[ingredient.name] = {

      ...ingredient,

      quantity

    }

  }


  onCheckRecipe(e) { // you'll want to add a type for e here

    for (let recipe of this.loadedRecipes) {

      // find the matching recipe

        if (recipe.name === e.detail.value) {

          // loop through the recipe ingredients

          for (let eachIngredient of recipe.ingredients) {

            this.toggleIngredient(eachIngredient, e.detail.checked)

          }

        }

      }

  }

}



查看完整回答
反对 回复 2023-03-24
?
汪汪一只猫

TA贡献1898条经验 获得超8个赞

我认为问题似乎出在代码的这一部分


if (

  matched.name === eachIngredient.name &&

  matched._id === eachIngredient._id

) {

  let index = this.groceryList.findIndex(

    (x) => x._id === matched._id

  );

  // Problem e ca eachIngredient.quantity se schimba

  this.groceryList.splice(index, 1);

} else {

  matched.quantity = matched.quantity - eachIngredient.quantity;

}

  1. if 语句应该检查数量而不是再次验证名称和 id ,比如

    if(matched.quantity <= eachIngredient.quantity){ // 拼接项目并删除它。} else { // 减少数量 }

  2. 找到匹配成分的小建议。先用findIndex()检索matchedIndex,再用grocerylist[matchedIndex]检索item,避免再次遍历grocerylist寻找索引进行拼接。


查看完整回答
反对 回复 2023-03-24
  • 2 回答
  • 0 关注
  • 103 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信