C# 用C从一个列表中排除另一个列表中的项目#

C# 用C从一个列表中排除另一个列表中的项目#,c#,winforms,list,optimization,C#,Winforms,List,Optimization,关于如何从一个列表中排除另一个列表中的项目,我有一个相当具体的问题。诸如Except()之类的常用方法行不通,原因如下: 如果列表中的副本有一个“偶数”索引,我需要删除这个元素和它后面的下一个元素 如果列表中的副本有一个“奇数”索引,我需要删除这个元素和它前面的一个元素 同一个重复项在列表中可能有许多外观。i、 一个指数可能是“奇数”,另一个指数可能是“偶数” 我不是在要求一个解决方案,因为我自己创造了一个。然而,在多次执行此方法之后,“ANTS performance profiler”显

关于如何从一个列表中排除另一个列表中的项目,我有一个相当具体的问题。诸如Except()之类的常用方法行不通,原因如下:

  • 如果列表中的副本有一个“偶数”索引,我需要删除这个元素和它后面的下一个元素
  • 如果列表中的副本有一个“奇数”索引,我需要删除这个元素和它前面的一个元素
  • 同一个重复项在列表中可能有许多外观。i、 一个指数可能是“奇数”,另一个指数可能是“偶数”
我不是在要求一个解决方案,因为我自己创造了一个。然而,在多次执行此方法之后,“ANTS performance profiler”显示该方法占用了整个执行时间的75%(40次中有30秒)。问题是:有没有更快的方法来执行相同的操作?我已经尝试优化我当前的代码,但它仍然缺乏性能。这是:

private void removedoubles(List<int> exclude, List<int> listcopy)
{
    for (int j = 0; j < exclude.Count(); j++)
    {
        for (int i = 0; i < listcopy.Count(); i++)
        {
            if (listcopy[i] == exclude[j])
            {
                if (i % 2 == 0) // even
                {
                    //listcopy.RemoveRange(i, i + 1);
                    listcopy.RemoveAt(i);
                    listcopy.RemoveAt(i);
                    i = i - 1;
                }
                else //odd
                {
                    //listcopy.RemoveRange(i - 1, i);
                    listcopy.RemoveAt(i - 1);
                    listcopy.RemoveAt(i - 1);
                    i = i - 2;
                }
            }
        }
    }
}
private void removedoubles(列表排除,列表复制)
{
对于(int j=0;j
其中:

  • 排除-仅包含重复项的列表。此列表最多可包含30个元素
  • listcopy—应检查重复项的列表。如果发现“排除”中的重复项->执行删除操作。此列表最多可包含2000个元素

我认为LINQ可能会有所帮助,但我不太理解它的语法。

反转循环,使循环从
.Count-1
开始,然后转到0,这样在其中一种情况下就不必更改
I
,并且
Count
只在每个集合中计算一次

更快的方法(
O(n)
)是执行以下操作:

  • 浏览
    exclude
    列表并将其放入
    HashSet
    O(n)
  • 在检查中,检查被测试的元素是否在集合中(再次
    O(n)
    ),因为在
    HashSet
    中存在的测试是
    O(1)
  • 也许您甚至可以更改算法,使
    exclude
    集合从一开始就是一个
    HashSet
    ,这样您就可以省略步骤1并获得更快的速度

    (您当前的方式是
    O(n^2)


    编辑:
    另一个想法是:您可能正在创建某个列表的副本,并让此方法修改它?(根据参数名进行猜测。)然后,您可以将其更改为:将原始数组传递给该方法,并使该方法分配新数组并返回它(您的方法签名应该是类似于
    private List getWithoutDoubles(HashSet exclude,List original)


    编辑:
    如果您以以下方式重新组织输入数据,则速度可能会更快:由于项目总是成对删除(偶数索引+以下奇数索引),因此您应该提前将它们配对!因此,如果int的列表变为int对的列表。这样,您的方法可能类似于:

    private List<Tuple<int, int>> getWithoutDoubles(
                  HashSet<int> exclude, List<Tuple<int, int>> original)
    {
        return original.Where(xy => (!exclude.Contains(xy.Item1) &&
                                     !exclude.Contains(xy.Item2)))
               .ToList();
    }
    
    private List getwithout doubles(
    哈希集排除,列表原始)
    {
    返回原始.Where(xy=>(!exclude.Contains(xy.Item1))&&
    !exclude.Contains(xy.Item2)))
    .ToList();
    }
    

    (删除排除集合中第一项或第二项所在的对)。您可以将项目打包为自定义类型,而不是
    元组。

    您可以将列表转换为LinkedList并试一试吗?List.RemoveAt()比LinkedList.Remove()更昂贵

    这里是获得结果的另一种方法

    var a = new List<int> {1, 2, 3, 4, 5};
    
    var b = new List<int> {1, 2, 3};
    
    var c = (from i in a let found = b.Any(j => j == i) where !found select i).ToList();
    
    var a=新列表{1,2,3,4,5};
    var b=新列表{1,2,3};
    var c=(在let found=b.Any(j=>j==i)中,其中!found select i.ToList();
    

    c将包含4,5

    粗体和大写字母,在我看来太多了。这是为了显示主要思想。无论如何,编辑了issueahh-永远不要更改
    for
    循环中的循环变量!使用while循环代替!您正在调用
    Count()
    方法,它是LINQ的一部分。这可能比简单地使用
    Count
    属性要慢,该属性已内置在
    列表中*去编码他不是在叫计数,他是在叫计数()
    。第一个只是
    List
    类的一个属性,另一个是LINQ-我想,将代码更改为使用该属性而不是方法将是一个很大的改进。@Alex:请注意,如果您是倒计时,您需要更改要删除的项的索引计算。这也很好,因为它只需要一个循环,并自动从“待删除”列表中删除两个循环。