什么是最好的方法去除的项目集合在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);

什么我真的想要做的就是找到该项目中删除的财产(在这种情况下,名称)没有通过循环的整个收集和使用2个额外变数。

有帮助吗?

解决方案

如果您想通过其中一个属性访问该集合的成员,则可以考虑使用Dictionary<T>KeyedCollection<T>。这样您就不必搜索您要查找的项目。

否则,你至少可以这样做:

foreach (SPRoleAssignment spAssignment in workspace.RoleAssignments)
{
    if (spAssignment.Member.Name == shortName)
    {
        workspace.RoleAssignments.Remove(spAssignment);
        break;
    }
}

其他提示

如果RoleAssignments是List<T>,您可以使用以下代码。

workSpace.RoleAssignments.RemoveAll(x =>x.Member.Name == shortName);

@smaclell问为什么反向迭代在对@ sambo99的评论中效率更高。

有时它更有效率。假设您有一个人员列表,并且您想删除或过滤所有信用评级为<!> lt;的客户; 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。我们最终错误地跳过了<=>。我们可以使用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);
}

对于一个简单的清单结构的最有效的方式似乎是使用所谓RemoveAll执行情况。

例如。

 workSpace.RoleAssignments.RemoveAll(x =>x.Member.Name == shortName);

原因是:

  1. 所谓/皇宫RemoveAll方法是实施列表,并访问内部阵列储存的实际数据。它将会转移数据和调整内部阵列。
  2. 该RemoveAt方法的实现是相当缓慢,并将拷贝的整个基础数据数组成一个新的阵列。这意味着扭转迭代是无用的清单

如果你坚持执行这一预c#3.0时代。你有2个选项。

  • 该易于维护的选择。复制所有匹配的项目进入一个新的清单和交换的基础名单。

例如。

List<int> list2 = new List<int>() ; 
foreach (int i in GetList())
{
    if (!(i % 2 == 0))
    {
        list2.Add(i);
    }
}
list2 = list2;

  • 棘手的速度稍快选项,其中涉及转换中的所有数据列表下来的时候它不匹配,然后调整数。

如果你移除的东西真的很频繁地从一个名单,也许是另一个结构像 HashTable (.净1.1)或 词典 (.网2.0)或 (.净3.5)更好地适合于这一目的。

如果是ICollection那么你将没有RemoveAll方法。这是一个扩展方法:

    public static void RemoveAll<T>(this ICollection<T> source, 
                                    Func<T, bool> 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过扩展换的收集级/

该系列是什么类型的?如果是List,您可以使用有用的<!>“RemoveAll <!>”:

int cnt = workspace.RoleAssignments
                      .RemoveAll(spa => spa.Member.Name == shortName)

(这适用于.NET 2.0。当然,如果你没有新的编译器,你必须使用<!> quot; delegate(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)会为您传入整数索引。

这是我的通用解决方案

public static IEnumerable<T> Remove<T>(this IEnumerable<T> items, Func<T, bool> match)
    {
        var list = items.ToList();
        for (int idx = 0; idx < list.Count(); idx++)
        {
            if (match(list[idx]))
            {
                list.RemoveAt(idx);
                idx--; // the list is 1 item shorter
            }
        }
        return list.AsEnumerable();
    }

如果扩展方法支持通过引用传递,那么看起来会更简单! 用法:

var result = string[]{"mike", "john", "ali"}
result = result.Remove(x => x.Username == "mike").ToArray();
Assert.IsTrue(result.Length == 2);

编辑:确保即使通过递减索引(idx)删除项目,列表循环仍然有效。

这是一个非常好的方法

http://support.microsoft.com/kb/555972

        System.Collections.ArrayList arr = new System.Collections.ArrayList();
        arr.Add("1");
        arr.Add("2");
        arr.Add("3");

        /*This throws an exception
        foreach (string s in arr)
        {
            arr.Remove(s);
        }
        */

        //where as this works correctly
        Console.WriteLine(arr.Count);
        foreach (string s in new System.Collections.ArrayList(arr)) 
        {
            arr.Remove(s);
        }
        Console.WriteLine(arr.Count);
        Console.ReadKey();

根据您使用收藏的方式,您可以采取另一种方法。如果您正在下载作业一次(例如,当应用程序运行时),您可以动态地将集合翻译成哈希表,其中:

shortname = <!> gt; SPRoleAssignment

如果您这样做,那么当您想要通过短名称删除项目时,您需要做的就是按键从哈希表中删除该项目。

不幸的是,如果您正在加载这些SPRoleAssignments,那么就时间而言,这显然不会更具成本效益。如果你使用新版本的.NET Framework,那么其他人对使用Linq的建议会很好,但除此之外,你必须坚持使用你正在使用的方法。

这里有很多好的回应;我特别喜欢lambda表达式......非常干净。但是,我没有指定Collection的类型。这是一个SPRoleAssignmentCollection(来自MOSS),只有Remove(int)和Remove(SPPrincipal),而不是方便的RemoveAll()。所以,我已经解决了这个问题,除非有更好的建议。

foreach (SPRoleAssignment spAssignment in workspace.RoleAssignments)
                        {
                            if (spAssignment.Member.Name != shortName) continue;
                            workspace.RoleAssignments.Remove((SPPrincipal)spAssignment.Member);
                            break;
                        }

要在循环遍历集合时执行此操作而不是修改集合异常,这是我过去采用的方法(注意原始集合末尾的.ToList(),这会创建另一个在内存中收集,然后你可以修改现有的集合)

foreach (SPRoleAssignment spAssignment in workspace.RoleAssignments.ToList()) { if (spAssignment.Member.Name == shortName) { workspace.RoleAssignments.Remove(spAssignment); } }

与Dictionary Collection相似,我已经做到了。

Dictionary<string, bool> sourceDict = new Dictionary<string, bool>();
sourceDict.Add("Sai", true);
sourceDict.Add("Sri", false);
sourceDict.Add("SaiSri", true);
sourceDict.Add("SaiSriMahi", true);

var itemsToDelete = sourceDict.Where(DictItem => DictItem.Value == false);

foreach (var item in itemsToDelete)
{
    sourceDict.Remove(item.Key);
}

注意: 上面的代码将在.Net Client Profile(3.5和4.5)中失败,也有一些观众提到它 在.Net4.0中失败了,不知道哪个设置导致问题。

所以用Where语句替换下面的代码(.ToList()),以避免该错误。 <!>#8220;收藏被修改;枚举操作可能无法执行。<!>#8221;

var itemsToDelete = sourceDict.Where(DictItem => DictItem.Value == false).ToList();

每个MSDN从.Net4.5开始,客户端配置文件已停止。 http://msdn.microsoft.com/en-我们/库/ cc656912(v = vs.110)的.aspx

首先保存您的项目,而不是删除它们。

var itemsToDelete = Items.Where(x => !!!your condition!!!).ToArray();
for (int i = 0; i < itemsToDelete.Length; ++i)
    Items.Remove(itemsToDelete[i]);

您需要覆盖Item类中的GetHashCode()

最好的方法是使用linq。

示例类:

 public class Product
    {
        public string Name { get; set; }
        public string Price { get; set; }      
    }

Linq查询:

var subCollection = collection1.RemoveAll(w => collection2.Any(q => q.Name == w.Name));

此查询将删除collection1中的所有元素,如果Name匹配来自collection2的任何元素using System.Linq;

请记住使用:<=>

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top