Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从集合中查找和删除项目_C#_Linq - Fatal编程技术网

C# 从集合中查找和删除项目

C# 从集合中查找和删除项目,c#,linq,C#,Linq,从集合中删除集合,但仍保留在单独集合中删除的项目的最佳方法是什么 我已经写了一个扩展方法来实现这一点,但我认为一定有更好的方法。以下是我的功能: public static List<T> FindAndRemove<T>(this List<T> lst, Predicate<T> match) { List<T> ret = lst.FindAll(match); lst.RemoveAll(match);

从集合中删除集合,但仍保留在单独集合中删除的项目的最佳方法是什么

我已经写了一个扩展方法来实现这一点,但我认为一定有更好的方法。以下是我的功能:

public static List<T> FindAndRemove<T>(this List<T> lst, Predicate<T> match)
{
    List<T> ret = lst.FindAll(match);
    lst.RemoveAll(match);
    return ret;
}
公共静态列表FindAndRemove(此列表lst,谓词匹配)
{
列表ret=lst.FindAll(匹配);
1.移除所有(匹配);
返回ret;
}
你可以这样使用它:

List<String> myList = new List<String>();
myList.Add("ABC");
myList.Add("DEF");
myList.Add("ABC");
List<String> removed = myList.FindAndRemove(x => x == "ABC");
// myList now contains 1 item (DEF)
// removed now contains 2 items (ABC, ABC)
    var ret = new List<T>(); 
    var remaining = new List<T>(); 
    foreach (T t in lst) {
        if (match(t)) 
        { 
            ret.Add(t); 
        } 
        else 
        { 
            remaining.Add(t); 
        } 
    }
    lst.Clear();
    lst.AddRange(remaining);
    return ret; 
List myList=new List();
myList.Add(“ABC”);
myList.添加(“定义”);
myList.Add(“ABC”);
移除列表=myList.FindAndRemove(x=>x==“ABC”);
//myList现在包含1项(DEF)
//已删除现在包含2项(ABC,ABC)

我不能100%确定
FindAll
RemoveAll
方法的幕后活动,但我认为更好的方法是以某种方式将项目从一个列表“转移”到另一个列表。

我不认为这是最有效的方法-您在列表的每个元素上调用谓词
match

我会这样做:

List<String> myList = new List<String>();
myList.Add("ABC");
myList.Add("DEF");
myList.Add("ABC");
List<String> removed = myList.FindAndRemove(x => x == "ABC");
// myList now contains 1 item (DEF)
// removed now contains 2 items (ABC, ABC)
    var ret = new List<T>(); 
    var remaining = new List<T>(); 
    foreach (T t in lst) {
        if (match(t)) 
        { 
            ret.Add(t); 
        } 
        else 
        { 
            remaining.Add(t); 
        } 
    }
    lst.Clear();
    lst.AddRange(remaining);
    return ret; 
var ret=newlist();
var剩余=新列表();
foreach(第一层中的T){
if(匹配(t))
{ 
再加上(t);
} 
其他的
{ 
剩余。添加(t);
} 
}
lst.Clear();
一级添加范围(剩余);
返回ret;

根据集合的大小,您可能希望将其实现为哈希集而不是列表。在足够大的集合中(根据我的经验,“足够”的大小多少在某种程度上取决于集合中的内容),哈希集在查找自身中的项时可以比列表快得多

Op的答案是迄今为止提出和建议的解决方案中最好的。以下是我的机器上的计时:

public static class Class1
{
    // 21ms on my machine
    public static List<T> FindAndRemove<T>(this List<T> lst, Predicate<T> match)
    {
        List<T> ret = lst.FindAll(match);
        lst.RemoveAll(match);
        return ret;
    }

    // 538ms on my machine
    public static List<T> MimoAnswer<T>(this List<T> lst, Predicate<T> match)
    {
        var ret = new List<T>();
        int i = 0;
        while (i < lst.Count)
        {
            T t = lst[i];
            if (!match(t))
            {
                i++;
            }
            else
            {
                lst.RemoveAt(i);
                ret.Add(t);
            }
        }
        return ret;
    }

    // 40ms on my machine
    public static IEnumerable<T> GuvanteSuggestion<T>(this IList<T> list, Func<T, bool> predicate)
    {
        var removals = new List<Action>();

        foreach (T item in list.Where(predicate))
        {
            T copy = item;
            yield return copy;
            removals.Add(() => list.Remove(copy));
        }

        // this hides the cost of processing though the work is still expensive
        Task.Factory.StartNew(() => Parallel.ForEach(removals, remove => remove()));
    }
}

[TestFixture]
public class Tester : PerformanceTester
{
    [Test]
    public void Test()
    {
        List<int> ints = Enumerable.Range(1, 100000).ToList();
        IEnumerable<int> enumerable = ints.GuvanteSuggestion(i => i % 2 == 0);
        Assert.That(enumerable.Count(), Is.EqualTo(50000));
    }
}
公共静态类Class1
{
//21毫秒在我的机器上
公共静态列表FindAndRemove(此列表lst,谓词匹配)
{
列表ret=lst.FindAll(匹配);
1.移除所有(匹配);
返回ret;
}
//538ms在我的机器上
公共静态列表MimoAnswer(此列表lst,谓词匹配)
{
var ret=新列表();
int i=0;
而(i<1次计数)
{
T=lst[i];
如果(!匹配(t))
{
i++;
}
其他的
{
一、搬迁(一);
再加上(t);
}
}
返回ret;
}
//40毫秒在我的机器上
公共静态IEnumerable GuvanteSuggestion(此IList列表,Func谓词)
{
var removals=新列表();
foreach(列表中的T项,其中(谓词))
{
T拷贝=项目;
交回副本;
removals.Add(()=>list.Remove(copy));
}
//这隐藏了处理的成本,尽管这项工作仍然很昂贵
Task.Factory.StartNew(()=>Parallel.ForEach(removals,remove=>remove());
}
}
[测试夹具]
公共类测试员:PerformanceTester
{
[测试]
公开无效测试()
{
List ints=Enumerable.Range(11000.ToList();
IEnumerable enumerable=ints.GuvanteSuggestion(i=>i%2==0);
Assert.That(enumerable.Count(),Is.EqualTo(50000));
}
}

您应该尝试将原始列表划分为两个新列表。实现应该在任何IEnumerable上工作,而不仅仅是列表,并且应该假设源是不可变的。 请参阅关于分区的这篇文章: .
我想已经涵盖了。

您的解决方案是最有效的。您的实施在我看来很好。复制在.Net中是一种廉价的操作,因此没有理由进行“传输”(除非您需要某种线程/异常安全,即一个对象一次不在多个集合中),我同意。使用内置LINQ的目的是让生活更轻松。。场景后面发生的事情将是MS选择的最佳解决方案。因为您使用的是C#,这对眼睛来说很好,但VB会将您的查询以菊花链的形式链接起来。
return=lst.FindAll(match)。RemoveAll(match)
,以与读取代码样式保持一致。@ppumkin尽管不需要自定义扩展方法。您只需使用.Where()并使其不等于所需的值,然后列出它和BAM。在列表中迭代一次,并做最少的工作以获得所需的结果。什么是不喜欢的?@ppumkin:另一种方法是创建一个列表来保存找到的结果,然后在其中进行迭代,因为你不能在foreach中对列表进行变异。@Neil Moss-我从来没有说过这是错的。。我试图暗示它是旧的。。对但大多数情况下,它不是.NET结构。仅此而已:)-PS看起来像JAVA或C。在任何MS.NET考试中,这个答案都是错误的。。不是我的错。多亏DPedan检查了我之前提出的解决方案的执行时间-由于使用了RemoveAt(),所以执行速度非常慢-现在我修复了它。当谓词快时,上面的新解决方案与问题中的原始解决方案一样快,而当谓词慢时,新解决方案的速度大约是原始解决方案的两倍,因此它的执行控制着整个执行时间。不适用
HashSet
Contains
处速度很快。也就是说,查找指定项是否在集合中。问题是迭代集合,查找与谓词匹配的成员;这样做不涉及使用
Contains