Удалить объект из общего списка по идентификатору
У меня есть класс домена следующим образом:
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
. Есть ли более элегантный способ обойти это?
Ответы
Ответ 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);
}