Вилучити елемент зі списку залежно від умови


78

У мене така структура:

public struct stuff
{
    public int ID;
    public int quan;
}

і хочу видалити продукт там, де IDє 1.
Я намагаюся це зараз:

prods.Remove(new stuff{ prodID = 1});

і це не працює.

ДЯКУЮ ВСІМ

Відповіді:


66

Використання linq:

prods.Remove( prods.Single( s => s.ID == 1 ) );

Можливо, ви навіть хочете використовувати SingleOrDefault() та перевірити, чи існує елемент взагалі ...

EDIT:
оскільки stuffє структурою, SingleOrDefault()не повертає значення null. Але він поверне за замовчуванням (stuff) , який матиме ідентифікатор 0. Коли у вас немає ідентифікатора 0 для ваших звичайних предметів-предметів, ви можете зробити запит для цього ідентифікатора:

var stuffToRemove = prods.SingleOrDefault( s => s.ID == 1 )
if( stuffToRemove.ID != 0 )
{
    prods.Remove( stuffToRemove );
}

1
Практично впевнений, що Remove (null) видає виняток, який виключає SingleOrDefault там, де він є.
Matt Mitchell,

2
@Graphain: Я додав для вас приклад
танацій

1
Або, можливо, більш читабельний if (stuffToRemove != default(stuff)).
Руфус Л

210

Якщо ваш тип колекції a List<stuff>, то найкращий підхід, мабуть, такий:

prods.RemoveAll(s => s.ID == 1)

Це робить лише один прохід (ітерацію) по списку, тому повинен бути ефективнішим за інші методи.

Якщо ваш тип більш загальний ICollection<T>, це може допомогти написати короткий метод розширення, якщо ви дбаєте про продуктивність. Якщо ні, то ви, мабуть, уникнете, використовуючи LINQ (дзвінок Whereабо Single).


5
Цю відповідь не можна прийняти, оскільки IList не має RemoveAll. У розпоряднику теми не вказано, що у нього є: List <T> або IList <T>.
Євгеній Набоков

5
"Не вдається"? Ха-ха. Не будьте педантичними. Навіть якщо автор працює з IList, RemoveAll досить тривіально реалізувати.
Noldorin

5

Якщо у вас є LINQ:

var itemtoremove = prods.Where(item => item.ID == 1).First();
prods.Remove(itemtoremove)

Ви можете поставити свій whereзапит як параметр до First ()
Matt Mitchell

Або ви можете просто замінити WhereнаFirst
Руфус Л


1

Ось рішення для тих, хто хоче видалити його з бази даних за допомогою Entity Framework :

prods.RemoveWhere(s => s.ID == 1);

І сам метод розширення:

using System;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;

namespace LivaNova.NGPDM.Client.Services.Data.Extensions
{
    public static class DbSetExtensions
    {
        public static void RemoveWhere<TEntity>(this DbSet<TEntity> entities, Expression<Func<TEntity, bool>> predicate) where TEntity : class
        {
            var records = entities
                .Where(predicate)
                .ToList();
            if (records.Count > 0)
                entities.RemoveRange(records);
        }
    }
}

PS Це імітує метод RemoveAll(), недоступний для наборів БД сутності сутності.


0

prods.Remove(prods.Single(p=>p.ID == 1));

ви не можете змінити колекцію в foreach, як пропонує Вінсент


Одномісний буде повільнішим, ніж перший, але він гарантує, що у вас немає дублікатів продуктів для того самого ідентифікатора, що, можливо, потрібно перевірити.
Matt Mitchell

0

Ви можете видалити лише те, на що у вас є посилання. Тож вам доведеться здійснити пошук по всьому списку:

stuff r;
foreach(stuff s in prods) {
  if(s.ID == 1) {
      r = s;
      break;
  }
}
prods.Remove(r);

або

for(int i = 0; i < prods.Length; i++) {
    if(prods[i].ID == 1) {
        prods.RemoveAt(i);
        break;
    }
}

хіба не швидше використовувати функцію find або findIndex у списку, замість того, щоб переглядати її?
Роб

1
Ви не можете змінити колекцію, яку повторюєте,
Matt Mitchell,

@Rob, для List, find повинен бути однаковим.
Matt Mitchell

@Graphain ой. @Rob, так, знахідка, мабуть, краща.
Вінсент Мак-Набб,

-2

Ви можете використовувати Linq.

var prod = from p in prods
           where p.ID != 1
           select p;

Це не призведе до видалення об’єкта. Якщо ви призначаєте, як prods = prods.Where(p != 1).ToList()вам ближче, але це не змінить список, який ви отримали як параметр.
Matt Mitchell
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.