Linq RemoveFirst 等效项

发布于 2024-10-06 04:17:47 字数 164 浏览 1 评论 0原文

我正在寻找 Linq RemoveFirst(Predicatematch) 但只能找到 RemoveAll

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

I was looking for a Linq RemoveFirst(Predicate<T> match) but could only find RemoveAll.

I know I can write my own extension method but was wondering if there already exists an equivalent function with a different name, or an easy way to achieve the same result.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

同展鸳鸯锦 2024-10-13 04:17:47

像这样:

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

如果没有找到项目,就会抛出异常。

请注意,这与 LINQ 无关,只能使用 List 来完成。

Like this:

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

If no item is found, an exception will be thrown.

Note that this has nothing to do with LINQ and can only be done with List<T>.

淡水深流 2024-10-13 04:17:47

这段代码实际上并没有从序列中“删除”元素,因为@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);
  }

This code does not actually "remove" the element from the sequence since, as @SLaks points out linq sequences are readonly, but it does skip the first occurrence of the element that meets the criteria. It is not particularly efficient as each list operation is going to iterate over the list. It is reasonably expressive of what you are trying to accomplish. Depending on how many items you expect to have in your list, this might be reasonable for you.

  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);
  }
情深如许 2024-10-13 04:17:47

由于没有其他人提供,这里是我的扩展方法/可枚举,它实现了RemoveFirst(Predicate match)。诀窍基本上是您需要定义自己的 IEnumerable 才能正确跟踪状态 - 我找不到解决这个问题的简单方法。

您可以在 此处的 .NET Fiddle 中尝试一下。

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

Since no one else has provided one, here's my extension method/enumerable that implements RemoveFirst(Predicate match). The trick is basically that you need to define your own IEnumerable to track the state properly--I couldn't find an easy way around that.

You can try it out in a .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; }
        }
    }
}
兔姬 2024-10-13 04:17:47

事实上,经典的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));
    }
}

Indeed the classic List has a RemoveAll(match) but not a RemoveFirst(match). An extension method could be

public static class ListExtensions
{
    public static void RemoveFirst<T>(this List<T> list, Predicate<T> match)
    {
        list.RemoveAt(list.FindIndex(match));
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文