C# 将RemoveAll限制为一定数量的对象
我正在使用一个包含父对象和子对象的C# 将RemoveAll限制为一定数量的对象,c#,lambda,removeall,C#,Lambda,Removeall,我正在使用一个包含父对象和子对象的列表。在此列表中,子对象知道其相关的父对象,反之亦然。使用这个列表,我试图实现一个业务规则,当其父对象属于某一类型时,将从列表中删除多达4个子对象。换句话说,如果此类型的父级有20个子级,则应从列表中删除其中的4个子级 var matches = myList.Where(item => item.Child && "Foo".Equals(item.Parent.SpecialType)).Take(someNumber).ToList(
列表
。在此列表中,子对象知道其相关的父对象,反之亦然。使用这个列表,我试图实现一个业务规则,当其父对象属于某一类型时,将从列表中删除多达4个子对象。换句话说,如果此类型的父级有20个子级,则应从列表中删除其中的4个子级
var matches = myList.Where(item => item.Child && "Foo".Equals(item.Parent.SpecialType)).Take(someNumber).ToList();
matches.ForEach(m => myList.Remove(m));
我在这里概述的代码将删除满足条件的所有子对象。这是意料之中的,但我想做的是将RemoveAll
限制为仅删除4个子项。是否有一种方法可以通过RemoveAll
实现这一点,或者是否有其他方法可以使用
myList.RemoveaAll(item =>
item.Child && "Foo".Equals(item.Parent.SpecialType));
为什么不使用Take
函数?使用Take扩展方法从IEnumerable中获取前n个匹配项。然后,您可以遍历匹配项并将其从列表中删除
var matches = myList.Where(item => item.Child && "Foo".Equals(item.Parent.SpecialType)).Take(someNumber).ToList();
matches.ForEach(m => myList.Remove(m));
哪4个重要吗?如果没有,您可以使用.Take(4)
创建一个包含4个子项的列表,然后遍历并删除4…尝试以下操作:
int i = 0;
myList.Removeall(item =>
item.Child && "Foo".Equals(item.Parent.SpecialType) && i++ < 4);
inti=0;
myList.Removeall(项目=>
item.Child&“Foo.Equals(item.Parent.SpecialType)&&i++<4);
请注意,我还没有测试它,但它应该可以工作您还可以编写一个扩展方法,在普通列表界面的基础上构建,如下所示:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace App
{
public static class ListExtension
{
public static int RemoveAll<T>(this List<T> list, Predicate<T> match, uint maxcount)
{
uint removed = 0;
Predicate<T> wrappingmatcher = (item) =>
{
if (match(item) && removed < maxcount)
{
removed++;
return true;
}
else
{
return false;
}
};
return list.RemoveAll(wrappingmatcher);
}
}
public interface IHero { }
public class Batman : IHero { }
public class HeroCompilation
{
public List<IHero> Herolist;
public HeroCompilation()
{
Herolist = new List<IHero>();
}
public void AddBatmans(int count){
for (int i = 1; i <= count; i++) Herolist.Add(new Batman());
}
}
class Program
{
static void ConsoleWriteBatmanCount(List<IHero> hero)
{
Console.WriteLine("There are {0} Batmans", hero.Count);
}
static void Main(string[] args)
{
HeroCompilation tester = new HeroCompilation();
ConsoleWriteBatmanCount(tester.Herolist);
tester.AddBatmans(10);
ConsoleWriteBatmanCount(tester.Herolist);
tester.Herolist.RemoveAll((x) => { return true; }, 4);
ConsoleWriteBatmanCount(tester.Herolist);
tester.Herolist.RemoveAll((x) => { return true; }, 4);
ConsoleWriteBatmanCount(tester.Herolist);
tester.Herolist.RemoveAll((x) => { return true; }, 4);
ConsoleWriteBatmanCount(tester.Herolist);
while (true) ;
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
命名空间应用程序
{
公共静态类ListExtension
{
公共静态int-RemoveAll(此列表、谓词匹配、uint-maxcount)
{
移除的uint=0;
谓词包装器=(项)=>
{
if(匹配(项目)&删除{return true;},4);
控制台WriteBatmanCount(tester.Herolist);
tester.Herolist.RemoveAll((x)=>{return true;},4);
控制台WriteBatmanCount(tester.Herolist);
虽然(正确);
}
}
}
Take不会修改列表。他想删除项目。Take不会修改列表。为了澄清,Take不会删除任何项目。您正在使用它来查找随后要删除的项目。只有一个问题:Take()
不迭代列表。因此,使用原样的代码,您可以在从列表中删除的同时迭代myList。这太糟糕了!我建议您在第一行中附加.ToList()
或.ToArray()
。事实上,我将继续为您添加它,如果您不同意,请随意回滚。通过@Randolpho的修改,这就像一个魅力。否则,在使用ForEach
之前,必须将.ToList追加到匹配项中。我从未见过Take
扩展方法。谢谢你指出这一点@Asteel:在调用Take()
后添加.ToList()
,或将其附加到匹配项中
完成相同的任务;唯一改变的是,在这么短的时间内,匹配的类型实际上是什么。您也可以简单地在一行中完成它:myList.Where(item=>item.Child&“Foo.Equals(item.Parent.SpecialType)).Take(someNumber.ToList().ForEach(m=>myList.Remove(m))代码>不进行测试,i
是否会在每次迭代时重置为0?第一次发现它似乎有用,但之后就不行了。