如何在数组中根据匹配的属性删除对象?

17

请考虑以下数据:

food = {
  id: 1,
  name: 'Pizza',
  price: 16
};

orders = [
  { food_id: 2, table_id: 5 },
  { food_id: 2, table_id: 5 },
  { food_id: 1, table_id: 5 },
  { food_id: 3, table_id: 5 },
  { food_id: 1, table_id: 5 }
];

我想要从 orders 数组中删除匹配 food_id 的一个项目。这是我尝试过的:

removeFoodOrder(food: Food): void {
  for (let order of this.orders) {
    let match = this.orders.filter((order) => order.food_id == food.id);
    match ? this.orders.splice(this.orders.indexOf(order), 1) : null;
    break;
  }
  console.log(this.orders);
}

如果我调用 removeFoodOrder(food),无论我传入什么食物项参数,它都会从数组中删除第一个元素。

removeFoodOrder(food) 
// removes {food_id: 2, table_id: 5} (the first element)
// I want to remove {food_id: 1, table_id: 5},

我想从数组中针对匹配的元素并移除其中的一个实例。我哪里做错了吗?


它正在删除数组的第一个元素,因为您已经使用过滤器删除了该项(我没有测试您的代码,但我非常确定这就是原因)。 - Gab
2
你的循环中有一个无条件的中断,并且你正在极其可疑地使用三元运算符。 - Aluan Haddad
1
@AluanHaddad 我完全同意。那只会增加混乱。 - Gab
3个回答

44
你可以使用 Array#filter 方法:
food = {
  id: 1,
  name: 'Pizza',
  price: 16
};

orders = [
  { food_id: 2, table_id: 5 },
  { food_id: 2, table_id: 5 },
  { food_id: 1, table_id: 5 },
  { food_id: 3, table_id: 5 },
  { food_id: 1, table_id: 5 }
];

removeFoodOrder(food: Food): void {
  this.orders = this.orders.filter(({ food_id }) => food_id !== food.id);        
}

编辑:

由于您的数组允许重复元素,并且您只想删除第一个匹配项,因此您可以使用 Array#findIndex + Array#filter 方法:

const foundIndex = this.orders.findIndex(({ food_id }) => food_id === food.id);
this.orders = this.orders.filter((_, index) => index !== foundIndex);

过滤器会过滤掉所有匹配的元素。我只想删除一个匹配的元素。 - anonym
当然是第一个。在订单数组中可能会有许多 {food_id: 2, table_id: 5} 的重复项,我只想删除其中一个。这可行吗? - anonym
好的,“filter”方法会删除所有符合特定条件的元素。由于您的“array”允许重复,因此请检查具有传统“for循环”替代方案的编辑版本。 - developer033
1
非常感谢你!这正是我一直在寻找的。 - anonym
很高兴它有帮助 :) - developer033
显示剩余3条评论

3

对我来说,第一步总是要删除任何类似于三元运算符和break语句这样的令人困惑的内容。以下是我的做法:

let food = {
  id: 1,
  name: 'Pizza',
  price: 16
}

let orders = [
    {food_id: 2, table_id: 5},
    {food_id: 2, table_id: 5},
    {food_id: 1, table_id: 5},
    {food_id: 3, table_id: 5},
    {food_id: 1, table_id: 5}
]

for (let order of this.orders) {
    if (food.id === order.food_id) {
        this.orders.splice(this.orders.indexOf(order), 1);
        break;
    }
}
console.log(this.orders);

我建议如果您不完全知道如何使用,就不要使用Array#filter。 更新:我并不是说不要使用Array#filter方法。我只是说,如果您的代码无法正常工作,您应该尝试删除可能导致问题的任何内容,并尝试使用简单结构(例如for循环和if语句)逐步进行。

1
问题不在于你是否应该使用过滤器,而在于你想要做什么。如果你想创建一个没有某个项目的新数组,那么过滤器就是正确的选择。 - Aluan Haddad
1
@AluanHaddad 你说得完全正确。我想我本意是说,解决这类问题最快的方法是排除任何自己不完全理解的东西,并尝试使用基本结构来修复它。 - Gab
1
这个答案是正确的,可行的,并且比其他答案要好得多,但我认为你不应该让人们远离filter,因为它是一个非常优雅和有用的函数。虽然在这里可能不是正确的选择。只是备注一下。 - Aluan Haddad
1
这取决于元素是否唯一。如果不是,那么不行(除非你对它进行不可描述的操作)。如果是唯一的,则可以像预期的那样使用过滤器。 - Gab
1
我刚刚注意到这个答案存在一个很大的问题,并建议进行编辑。这个答案的打字比原始问题要差。去掉任何不必要的东西。 - Aluan Haddad
显示剩余3条评论

1

试试这个:

function removeFoodOrder(food: Food): void
{
    for (let order of this.orders) {
        if (order.food_id == food.id) {
            this.orders.splice(this.orders.indexOf(order), 1);
            break;
        }      
    }
    console.log(this.orders);
};

@AluanHaddad,您能否详细说明一下“风格不佳”的含义? - Girisha
1
使用==以及添加不相关的抽象和不必要的类型注释。 - Aluan Haddad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接