【问题标题】:C# List removeall taking two arguments in the predicate?C# List removeall 在谓词中采用两个参数?
【发布时间】:2013-06-24 23:38:45
【问题描述】:

(我已经根据“removeall where”或“removeall two argument predicate”的关键字进行了尽可能多的搜索,但运气不佳,所以这里是这样)

问题是我有一个对象列表(类 Wave)和一个关系函数: private bool AinB(Wave A, Wave B),如果 A '在' B 中,则返回 true。AinB(x,y) 为 true 保证 AinB(y,x) 为 false。

删除列表中对象“位于”列表中另一个对象中的所有对象的最佳方法是什么?即,在删除之后,列表应该只包含与列表中的任何其他对象都不存在“存在”关系的对象?

理想情况下,这可以轻松完成

listX.RemoveAll( (x,y) => AinB(x,y)) 但当然这在 C# 中是不合法的,也没有简单的方法来指定要删除哪个,x 或 y。

我想过用索引循环遍历列表

int i = listX.Count - 1;
while (i>=0)
{
    int r = listX.RemoveAll(X => AinB(X, listX[i]));
    i = i - r - 1;
}

这似乎可行,但我想知道是否有更好的方法使用直接 linq 代码来解决问题。 谢谢。

【问题讨论】:

  • 听上去你正在建造一棵树,这是正确的吗?我在回答中假设 AinB 正在检查树的节点并确定 A 是否是 B 的子节点。
  • 不,它相当复杂,而且这个“过滤器”只是“关系”之一,但却是过滤掉大部分对象的主要关系。

标签: c# list removeall


【解决方案1】:

使用正常的 for 循环,首先检查列表中的最高元素,直到最低元素。检查当前位置的元素是否存在列表中的任何重复项,如果发现删除当前元素(并可能减少您的迭代器)。

例子:

List<string> stuff = new List<string>(); //full of stuff
for(int i = stuff.Count - 1; i > 0; i--)
{
    //Edited here for more efficiency.
    for (int x = i - 1; x > 0; x--)
    {
        if (stuff[x] == stuff[i])
        {
            stuff.RemoveAt(i);
            break; //or possibly continue;
        }
    }
}

这里是手动编码的,因此可能存在一些语法错误,如果您发现某些地方不太正确,请随时给我编辑。

如果您是使用 LINQ 的向导,您还可以尝试将列表中的对象分组,然后选择每个组中的第一个对象作为输出列表。

【讨论】:

  • 可能有人不喜欢 for/i/x.. 现在人们往往不喜欢命令式的方式
  • 我很确定 LINQ 比 double for 慢得多。人们过于依赖 c# 中的一个衬里。
  • 这是正确的吗?删除完成后,列表大小会减小,并且您仍在基于原始索引进行循环?
  • Izzy:很多时候数据集很小,因此可读性要重要得多。对于大集合,速度首先来自减少问题集,然后来自算法“形状”,最后来自算法的实现。您的形状与其他人的建议非常接近。从头/尾扫描,提前休息等等。恕我直言,这一切都使悲观的 0.5*n^2。有人可能会针对某些特定分布进行优化,但没有人会期待西班牙宗教裁判所,因此悲观的案例只会出现并消失。我实际上喜欢未优化的 1-linears,因为它们首先会迫使您检查问题。
【解决方案2】:

不幸的是,我想不出至少不是 O(n^2) 的任何方法。但好消息是,从 LINQ 的角度来看,这并不难:

listX.RemoveAll(item => listX.Any(isin => AinB(item, isin)));

【讨论】:

  • 这似乎是我要找的那个。假设 listX 具有被排序的属性,其中末尾的元素在前面“封闭”元素的可能性更高,我如何强制评估从列表的末尾回到列表的前面,就像在我的原始循环中一样。
  • 有了这些功能,你就不行了。您可以尝试 Reverse,但这并不能保证 'removeall' 会以任何顺序访问任何内容。
【解决方案3】:

你可以使用 LINQ except 调用,

List a = new List();
a.Add("a");
a.Add("b");
a.Add("c");
List b = new List();
b.Add("b");
b.Add("c");
b.Add("d");
List c = a.Except(b);

列表 c 将只包含项目“a”;

你甚至可以通过提供一个比较对象来让它更聪明,

List c = a.Except(b, new CompareObject());

【讨论】:

  • 我认为您需要更仔细地重新阅读该问题。这不仅仅是设定差异。
  • @quetzalcoatl 那是什么?
  • 这也不是只是集的差异,因为另一集还未知,必须确定。如果您想回答,请解释如何准备比较器,以便它执行所需的检查。目前,你只有 50% 的答案。我不要求代码,只是一些简短的解释。
猜你喜欢
  • 2011-03-05
  • 2018-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多