web-dev-qa-db-ja.com

IDでジェネリックリストからオブジェクトを削除します

私はこのようなドメインクラスを持っています:

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

しかし、IListListとしてキャストすることはできません。これを回避するためのよりエレガントな方法はありますか?

14
gdp

不要なアイテムを除外して、必要なアイテムのみを含む新しいリストを作成できます。

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

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

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に感謝します。

10
Vercas

手動でコーディングすることもできます。単純な実装は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)であることを意味します。

2
CodesInChaos

データ構造を変更できる場合は、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>>を使用してください。

2
Magnus

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

削除するアイテムの配列を受け取ることができます。ループ内のリストからそれらを削除するよりも。このサンプルを見てください:

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