私はこのようなドメインクラスを持っています:
public class DomainClass
{
public virtual string name{get;set;}
public virtual IList<Note> Notes{get;set;}
}
IList<Note>
からアイテムを削除するにはどうすればよいですか?リストであればそれは可能ですが、永続層にNhibernateを使用しているため、IList
である必要があります。
理想的には、ドメインクラスに次のようなメソッドが必要でした。
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
としてキャストすることはできません。これを回避するためのよりエレガントな方法はありますか?
不要なアイテムを除外して、必要なアイテムのみを含む新しいリストを作成できます。
public virtual void RemoveNote(int id)
{
//remove the note from the list here
Notes = Notes.Where(note => note.Id != id).ToList();
}
Edit2:このメソッドはaList
!にキャストする必要はありません
foreach (var n in Notes.Where(note => note.Id == id).ToArray()) Notes.Remove(n);
または...
Notes.Remove(Notes.Where(note => note.Id == id).First());
最初のものが最高です。
そのid
を持つノートがない場合、2番目のものは例外をスローします。
編集:私の間違いを示してくれたMagnusとrsbarroに感謝します。
手動でコーディングすることもできます。単純な実装はO(n * k)で、nはリスト内のアイテムの数、kは削除するアイテムの数です。 1つのアイテムだけを削除したい場合は、高速です。
しかし、多くのアイテムを削除したい場合、ネイティブ実装は多くの_IList<T>
_実装(_List<T>
_を含む、NHibernateのリストがどのように動作するかわからない)に対してO(n^2)
になり、少し書く必要がありますO(n)
RemoveAll
実装を取得するためのより多くのコード。
古い答えからの1つの可能な実装: リスト、参照を失うことはありません
この実装の秘訣は、保持されているアイテムをO(n)のリストの先頭に移動することです。次に、リストの最後の項目(要素を移動する必要がないため、通常はO(1))を削除し続けるため、切り捨てはO(n)合計になります。これは、アルゴリズム全体がO(n)であることを意味します。
データ構造を変更できる場合は、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>>
を使用してください。
public virtualsを回避する方がよい場合があることを考慮してください。次のように、 テンプレートメソッド パターンを使用してください。
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);
}