найти и удалить из IList

#c# #linq-to-objects

#c# #linq-to-objects (привязка к объектам)

Вопрос:

У меня есть IList пользователей

 private IList<User> _Players
  

У меня есть способ удалить конкретного пользователя из списка

 public virtual void RemovePlayer(User User)
{
    int index=_Players.Select(T=>T.ID).ToList().IndexOf(User.ID);
    _Players.RemoveAt(index);
}
  

Я хотел бы знать, есть ли более простой способ удалить пользователя из этого списка

Ответ №1:

Как насчет этого? Используйте это, если ваш параметр User не является частью _Players .

  _Players.Remove(_Players.SingleOrDefault(x => x.ID == User.ID));
  

SingleOrDefault() Гарантирует, что если совпадение не найдено, возвращается значение null. При попытке удалить null ошибка не возникает и не выдается.

Ответ №2:

Если User используемые вами объекты хранятся в _ Players списке (те же ссылки на объекты), вы можете просто сделать

 _Players.Remove(user);
  

В противном случае, если совпадает только идентификатор, вы можете сделать:

 _Players.RemoveAll( p => p.ID == user.ID);
  

Комментарии:

1. removeAll не работает с IList, что и было первоначальным вопросом.

2. Этот ответ не относится к исходному вопросу.

Ответ №3:

Существует два сценария, user переменная, которую вы передаете RemovePlayer

  1. на самом деле содержится в вашем списке
  2. имеет то же ID значение, но не является тем же объектом.

Из вашего примера кода невозможно сказать.

В первом случае просто вызовите _Players.Remove(user) . Во втором случае реализуйте System.IEquatable<User> интерфейс на User , чтобы определить значение по умолчанию EqualityComparer<User> , а затем снова вызовите _Players.Remove(user) . Этот второй сценарий работает в обоих случаях.

Комментарии:

1. это решение очень помогает, потому что я использую generics и могу удалять объекты без необходимости знать свойства, которые они содержат.

2. @David On ИТАК, люди голосуют, основываясь в первую очередь на оценке постера, а не на ответе; это хорошо видно здесь 🙂

Ответ №4:

Зависит от того, внедрили ли вы IEquatable для своего пользователя функцию сравнения по ID , тогда вы могли бы просто сделать _Players.Remove(user) .

В противном случае:

 var doomed = _Players.FirstOrDefault(p => p.ID == user.ID);
if (doomed != null)
   _Players.Remove(doomed);
  

Ответ №5:

Только в том случае, если у вас есть List<T> :

Все упомянутые алгоритмы с SingleOrDefault() / FirstOrDefault() требуют двух обходов по списку:

1) первый, кто найдет элемент по критериям

2) второй, чтобы найти индекс элемента по его значению, найденному на шаге # 1

Немного эффективнее сделать вот так вместо этого:

 int index = list.FindIndex(i => criteria);

if (index >= 0)
  list.RemoveAt(index);
  

Ответ №6:

Просто хотел сделать то же самое, но не смог найти стандартный способ.
Решил сам написать код для своих списков int. Этот маленький не будет выполнять двойной проход по списку!
Вы можете заменить int на object для работы с классами.

 public static bool FindAndRemoveFirst(this ICollection<int> list, Func<int, bool> predicate)
{
    var en = list.GetEnumerator();
    while (en.MoveNext())
    {
        if (predicate(en.Current))
        {
            list.Remove(en.Current);
            return true;
        }
    }
    return false;
}