Подтвердить что ты не робот

Удалить объект из общего списка по идентификатору

У меня есть класс домена следующим образом:

public class DomainClass
{
  public virtual string name{get;set;}
  public virtual IList<Note> Notes{get;set;}
}

Как я могу удалить элемент из IList<Note>? Я мог бы сделать это, если бы это был список, но он должен быть IList, поскольку я использую Nhibernate для моего уровня защиты.

В идеале мне нужен такой метод в моем классе домена:

public virtual void RemoveNote(int id)
{
   //remove the note from the list here

   List<Note> notes = (List<Note>)Notes

   notes.RemoveAll(delegate (Note note)
   {
       return (note.Id = id)
   });
}

Но я не могу использовать IList как List. Есть ли более элегантный способ обойти это?

4b9b3361

Ответ 1

Вы можете отфильтровать элементы, которые не хотите, и создать новый список только с теми предметами, которые вы хотите:

public virtual void RemoveNote(int id)
{
   //remove the note from the list here

   Notes = Notes.Where(note => note.Id != id).ToList();
}

Ответ 2

Edit2: этот метод не требует кастинга для List !

foreach (var n in Notes.Where(note => note.Id == id).ToArray()) Notes.Remove(n);

или...

Notes.Remove(Notes.Where(note => note.Id == id).First());

Первый - лучший.
Второй будет генерировать исключение, если нет примечаний, что id.

Изменить: спасибо Магнусу и rsbarro за то, что я показал свою ошибку.

Ответ 3

Вы можете запрограммировать его вручную. Наивная реализация - это O (n * k), где n - количество элементов в списке, а k - количество элементов, которые вы хотите удалить. Если вы хотите просто удалить один элемент, это быстро.

Но если вы хотите удалить много элементов, то встроенная реализация становится O(n^2) для многих реализаций IList<T> (включая List<T>, не знаю, как ведет себя список NHibernate), и вам нужно написать немного больше кода, чтобы получить O(n) RemoveAll.

Одна возможная реализация из старого ответа: Список, не теряющий ссылку

Трюк с этой реализацией заключается в том, что в перемещаемых элементах сохраняются элементы в начало списка в O (n). Затем он удаляет последний элемент списка (обычно это O (1), поскольку никакие элементы не должны перемещаться), поэтому усечение становится O (n). Это означает, что весь алгоритм O (n).

Ответ 4

Если вы можете изменить структуру данных, я бы предложил использовать Dictionary. Чем вы можете пойти:

public class DomainClass
{
  public virtual string name{get;set;}
  public virtual IDictionary<int, Note> Notes {get; set;}

  //Helper property to get the notes in the dictionary
  public IEnumerable<Note> AllNotes
  {
    get
    {
      return notes.Select (n => n.Value);
    }
  }

  public virtual void RemoveNote(int id)
  {
     Notes.Remove(id);
  }

}

Если идентификатор не уникален, используйте IDictionary<int, IList<Note>>.

Ответ 5

Пожалуйста, обратите внимание, что в некоторых случаях лучше избегать публичных виртуальных машин, используйте шаблонный метод таким образом:

 public void Load(IExecutionContext context) 
 { 
      // Can safely set properties, call methods, add events, etc...
      this.Load(context);            
      // Can safely set properties, call methods, add events, etc. 
 }

 protected virtual void Load(IExecutionContext context) 
 {
 }

Ответ 6

Вы можете получить массив элементов для удаления. Затем удалите их из списка в цикле. Посмотрите на этот образец:

IList<int> list = new List<int> { 1, 2, 3, 4, 5, 1, 3, 5 };

var valuesToRemove = list.Where(i => i == 1).ToArray();

foreach (var item in valuesToRemove)
{
    list.Remove(item);
}