Удалить объект из общего списка по ID

у меня есть домен класс, как это:

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

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

в идеале я хотел подобный метод в моем классе домена:

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. Есть ли более элегантный способ обойти это?

6 ответов


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

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

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

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.

Edit: спасибо Магнусу и rsbarro за то, что показали мою ошибку.


Если вы можете изменить структуру данных, я бы предложил использовать 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);
  }

}

Если ID не является уникальным, используйте IDictionary<int, IList<Note>> вместо.


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

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

одна возможная реализация из старого ответа:список, не потерять ссылку

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


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

 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) 
 {
 }

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

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);
}