一旦项目已知,但在C#中从集合中删除项目的最佳方法是什么,但不是它的索引.这是一种方法,但它似乎不够优雅.
//Remove the existing role assignment for the user. int cnt = 0; int assToDelete = 0; foreach (SPRoleAssignment spAssignment in workspace.RoleAssignments) { if (spAssignment.Member.Name == shortName) { assToDelete = cnt; } cnt++; } workspace.RoleAssignments.Remove(assToDelete);
我真正想做的是找到要按属性删除的项目(在本例中为name),而不循环遍历整个集合并使用另外两个变量.
如果RoleAssignments是a,List
您可以使用以下代码.
workSpace.RoleAssignments.RemoveAll(x =>x.Member.Name == shortName);
如果要通过其中一个属性访问集合的成员,可以考虑使用Dictionary
或KeyedCollection
替代.这样您就不必搜索您要查找的项目.
否则,你至少可以这样做:
foreach (SPRoleAssignment spAssignment in workspace.RoleAssignments) { if (spAssignment.Member.Name == shortName) { workspace.RoleAssignments.Remove(spAssignment); break; } }
@smaclell问为什么反向迭代在对@ sambo99的评论中更有效率.
有时它更有效率.假设您有一个人员列表,并且您想删除或过滤信用评级<1000的所有客户;
我们有以下数据
"Bob" 999 "Mary" 999 "Ted" 1000
如果我们要向前推进,我们很快就会遇到麻烦
for( int idx = 0; idx < list.Count ; idx++ ) { if( list[idx].Rating < 1000 ) { list.RemoveAt(idx); // whoops! } }
在idx = 0时,我们移除Bob
,然后将剩余的所有元素移开.下一次通过循环idx = 1,但list [1]现在Ted
而不是Mary
.我们最终Mary
错误地跳过了.我们可以使用while循环,我们可以引入更多变量.
或者,我们只是反向迭代:
for (int idx = list.Count-1; idx >= 0; idx--) { if (list[idx].Rating < 1000) { list.RemoveAt(idx); } }
已删除项目左侧的所有索引保持不变,因此您不会跳过任何项目.
如果给出要从数组中删除的索引列表,则同样的原则适用.为了保持正确,您需要对列表进行排序,然后将项目从最高索引删除到最低.
现在你可以使用Linq并以简单的方式声明你正在做的事情.
list.RemoveAll(o => o.Rating < 1000);
对于这种删除单个项目的情况,它不再有效地向前或向后迭代.您也可以使用Linq.
int removeIndex = list.FindIndex(o => o.Name == "Ted"); if( removeIndex != -1 ) { list.RemoveAt(removeIndex); }
对于简单的List结构,最有效的方法似乎是使用Predicate RemoveAll实现.
例如.
workSpace.RoleAssignments.RemoveAll(x =>x.Member.Name == shortName);
原因是:
Predicate/Linq RemoveAll方法在List中实现,并且可以访问存储实际数据的内部数组.它将移动数据并调整内部数组的大小.
RemoveAt方法实现非常慢,并将整个底层数据数据复制到一个新数组中.这意味着反向迭代对List无用
如果你在前c#3.0时代被卡住了.你有2个选择.
易于维护的选项.将所有匹配项复制到新列表中,并交换基础列表.
例如.
Listlist2 = new List () ; foreach (int i in GetList()) { if (!(i % 2 == 0)) { list2.Add(i); } } list2 = list2;
要么
棘手的稍微快一点的选项,它涉及在列表不匹配时将列表中的所有数据向下移动然后调整阵列大小.
如果你经常从列表中删除东西,可能另一个结构如HashTable(.net 1.1)或Dictionary(.net 2.0)或HashSet(.net 3.5)更适合这个目的.
如果是,ICollection
那么你将没有RemoveAll
方法.这是一个扩展方法,它将执行此操作:
public static void RemoveAll(this ICollection source, Func predicate) { if (source == null) throw new ArgumentNullException("source", "source is null."); if (predicate == null) throw new ArgumentNullException("predicate", "predicate is null."); source.Where(predicate).ToList().ForEach(e => source.Remove(e)); }
基于:http: //phejndorf.wordpress.com/2011/03/09/a-removeall-extension-for-the-collection-class/
这个系列是什么类型的?如果是List,您可以使用有用的"RemoveAll":
int cnt = workspace.RoleAssignments .RemoveAll(spa => spa.Member.Name == shortName)
(这适用于.NET 2.0.当然,如果你没有新的编译器,你将不得不使用"委托(SPRoleAssignment spa){return spa.Member.Name == shortName;}"而不是lambda语法.)
另一种方法,如果它不是List,但仍然是ICollection:
var toRemove = workspace.RoleAssignments .FirstOrDefault(spa => spa.Member.Name == shortName) if (toRemove != null) workspace.RoleAssignments.Remove(toRemove);
这需要Enumerable扩展方法.(如果您遇到.NET 2.0,可以复制Mono).如果它是一些无法获取项目的自定义集合,但必须采用索引,则其他一些Enumerable方法(如Select)会为您传入整数索引.