2010-12-07 13 views
2

私はLinq RemoveFirst(Predicate<T> match)を探していましたが、RemoveAllしか見つかりませんでした。Linq RemoveFirst相当

私は独自の拡張メソッドを書くことができますが、同じ名前の同等の関数が既に存在するのか、同じ結果を得るための簡単な方法が存在するのだろうかと思いました。このよう

+0

これはLINQではありません。それ以来、.Net 2.0。 – SLaks

+1

'RemoveAll'は' List 'のインスタンスメソッドです。これはLINQの一部ではありません。 – Ani

+0

これは、読み取り専用のインタフェースである 'IEnumerable 'とは関係ありません。 – SLaks

答えて

6

:項目が見つからない場合

list.RemoveAt(list.FindIndex(x => thingy)); 

は、例外がスローされます。

これはLINQとは無関係であり、List<T>でのみ行うことができます。

0

このコードでは、@SLaksがlinqシーケンスは読み込み専用であるが、基準を満たす要素の最初のオカレンスはスキップするため、実際には要素をシーケンスから "削除"しません。各リスト操作がリストを反復するので、特に効率的ではありません。あなたが達成しようとしていることを合理的に表現しています。あなたのリストにあると思われるアイテムの数に応じて、これはあなたにとって合理的かもしれません。

IEnumerable<int> x = Enumerable.Range(0, 20); 
    var y = x.TakeWhile(xx => xx < 10).Concat(x.SkipWhile(xx => xx < 10).Skip(1)); 

    //Will write 0 1 2 ... 19, skipping 10 
    foreach(int a in y) 
    { 
    System.Diagnostics.Debug.WriteLine(a); 
    } 
+0

これは非効率的です。何度もリストを列挙します。 – SLaks

+0

はい、私は私の答えでそれを指摘しました。 – wageoghe

0

誰もが1つを提供していないので、ここではremoveFirstと(述語の一致)を実装する列挙私の拡張メソッドは/です。トリックは基本的には、状態を正しく追跡するために独自のIEnumerableを定義する必要があるため、その周りを簡単に見つけることができませんでした。

.NET Fiddle hereで試してみることができます。

public static IEnumerable<T> RemoveFirst<T>(this IEnumerable<T> list, Func<T, bool> predicate) 
{ 
    return new RemoveFirstEnumerable<T>(list, predicate); 
} 

public static IEnumerable<T> RemoveFirst<T>(this IEnumerable<T> list, T item) 
{ 
    return RemoveFirst(list, x => Object.Equals(x, item)); 
} 
private class RemoveFirstEnumerable<T> : IEnumerable<T> 
{ 
    IEnumerable<T> m_Source; 
    Func<T, bool> m_Predicate; 

    public RemoveFirstEnumerable(IEnumerable<T> source, Func<T, bool> predicate) 
    { 
     m_Source = source; 
     m_Predicate = predicate; 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     return new RemoveFirstEnumerator(m_Source, m_Predicate); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return new RemoveFirstEnumerator(m_Source, m_Predicate); 
    } 

    private class RemoveFirstEnumerator : IEnumerator<T> 
    { 
     IEnumerator<T> m_Enumerator; 
     Func<T, bool> m_Predicate; 
     bool m_RemovedOnce = false; 
     public RemoveFirstEnumerator(IEnumerable<T> source, Func<T, bool> predicate) 
     { 
      m_Enumerator = source.Where(WherePredicate).GetEnumerator(); 
      m_Predicate = predicate; 
     } 

     bool WherePredicate(T current) 
     { 
      // terse version: 
      return m_RemovedOnce || !(m_RemovedOnce = m_Predicate(current)); 

      // Long version 
      //if (m_RemovedOnce) 
      //{ 
      // return true; 
      //} 
      //else 
      //{ 
      // m_RemovedOnce = Object.Equals(x, item); 
      // return !m_RemovedOnce; 
      //} 
     } 

     public T Current 
     { 
      get { return m_Enumerator.Current; } 
     } 

     public bool MoveNext() 
     { 
      return m_Enumerator.MoveNext(); 
     } 


     public void Reset() 
     { 
      m_Enumerator.Reset(); 
     } 

     public void Dispose() 
     { 
      m_Enumerator.Dispose(); 
     } 

     object IEnumerator.Current 
     { 
      get { return m_Enumerator.Current; } 
     } 
    } 
}