Linq RemoveFirst相当于

时间:2010-12-07 16:56:50

标签: linq lambda ienumerable

我正在寻找Linq RemoveFirst(Predicate<T> match),但只能找到RemoveAll

我知道我可以编写自己的扩展方法但是想知道是否已经存在具有不同名称的等效函数,或者是一种简单的方法来实现相同的结果。

4 个答案:

答案 0 :(得分:6)

像这样:

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

如果未找到任何项目,则会抛出异常。

请注意,这与LINQ无关,只能使用List<T>

答案 1 :(得分: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);
  }

答案 2 :(得分:0)

由于没有其他人提供过一个,这是我的扩展方法/枚举实现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; }
        }
    }
}

答案 3 :(得分:0)

实际上,经典List具有RemoveAll(match),但没有RemoveFirst(match)。扩展方法可能是

public static class ListExtensions
{
    public static void RemoveFirst<T>(this List<T> list, Predicate<T> match)
    {
        list.RemoveAt(list.FindIndex(match));
    }
}