使用LINQ或Lambda从列表中删除实例?

时间:2009-07-26 19:18:34

标签: c# linq lambda

现在我来了一个阶段,将我的所有数据作为缓存(对象)中的列表,我接下来要做的就是从列表中删除一些实例。

通常,我会像这样删除:

List<T> list;
List<T2> toBeRemovedItems;
// populate two lists
foreach(T2 item in toBeRemovedItems)
{
    list.Remove(delegate(T one) { 
        // build a condition based on item
        // return true or false
    });
}

更具体地说,我实际上构建或填充了动态类(不是正式定义的类)的BeRemvoedItems列表。例如,T类类似于MyClass,删除代码是:

class MyClass<C> {
    public string Value1 { get; set; }
    public int Value2 { get; set; }
    public C ObjectC { get; set; }
}
....
List<MyClass<C>> list;
// populate list
// populate toBeRemovedItems. Here is an example of hard-coded codes:
var toBeRemovedLItems = new[] {
    new { Value1="a", Value2 = 1},
    new { Value2="x", Value2 = 10},
    ...
};
// toBeRemovedItems may be the result of Select from a collection
foreach(var item in toBeRemovedLItems)
{
    list.Remove(delegate(MyClass one) {
        return one.Value1 = item.Value1 && one.Value2 < item.Value2;
    });
}

我尝试在MSDN中的Remove()界面中搜索IEnumerable方法,但我找不到Remove()的方法(IEnumerable只使用了Remove(...)列举)。在List类中,有几个重载的IEnumerable方法。我不确定是否有其他方法可以使用LINQ或Lambda表达式从列表中删除项目?

顺便说一句,我想到了一种方法来对列表进行查询,以获得具有Where条件的子集或新{{1}}列表,类似于从列表中移动项目。但是,我更喜欢从缓存列表中删除项目,在某些情况下,我无法将类中的列表属性重置为新列表(例如私有集)。

7 个答案:

答案 0 :(得分:41)

您可以使用 RemoveAll

方法
MyClass one; //initialize MyClass
list.RemoveAll(item => one.Value1 == item.Value1 && one.Value2 < item.Value2);

答案 1 :(得分:21)

您可以使用LINQ的Where方法过滤掉不应该是列表一部分的值。结果是IEnumerable<T>删除了元素。

var res = list.Where(item => !(one.Value1 == item.Value1 && one.Value2 < item.Value2));

这不会更新原始List<T>实例,而是会创建一个删除了值的新IEnumerable<T>

答案 2 :(得分:5)

如果我正确地得到了问题,要从两个List中生成一个唯一的集合。

为此,您可以使用以下

列表list1; 清单list2;

列表list3 = list1.Except(list2)

list3将包含唯一的项目。

答案 3 :(得分:4)

我同意Jared关于过滤掉某些项目的建议,但join Value1似乎是一种更有效的方法:

var res = from item1 in list
          join item2 in toBeRemovedList
            on item1.Value1 equals item2.Value1
          where item1.Value2 >= item2.Value2
          select item1;

更新:显然我在阅读理解上失败了 - 新方法:

var removeDict = toBeRemovedList.ToDictionary(i => i.Value1, i => i.Value2);
list.RemoveAll(item => {
    int itemToRemoveValue2;
    if(removeDict.TryGetValue(item.Value1, out itemToRemoveValue2))
        return item.Value2 < itemToRemoveValue2;
    return false;
});

当然,如果要删除的列表可以以字典开头,那就更好了。最终,我们只是想让Value1的匹配更有效率。

答案 4 :(得分:2)

foreach(var item in toBeRemovedLItems) {   
   list.RemoveAll(one => one.Value1 == item.Value1 && one.Value2 < item.Value2); 
}

再次太迟了。哦,好吧。

答案 5 :(得分:1)

对于非列表的集合(无法公开RemoveAll),您仍然可以删除带有单行的项目。

要替换内联,只需生成要删除的项目列表,然后运行它并执行删除代码。

var dictionary = new Dictionary<string, string>(){{"foo", "0"}, {"boo", "1"}, {"goo", "1"}};
dictionary
    .Where(where_item =>
        ((where_item.Key == "foo") && (where_item.Value == "0"))
        || ((where_item.Key == "boo") && (where_item.Value == "1"))
    )
    .ToList()
    .ForEach(remove_item => {
        dictionary.Remove(remove_item.Key);
    });

要替换副本,只需生成已过滤的可枚举项并返回新副本。

var dictionary0 = new Dictionary<string, string>(){{"foo", "0"}, {"boo", "1"}, {"goo", "1"}};
var dictionary1 = dictionary0
    .Where(where_item =>
        ((where_item.Key == "foo") && (where_item.Value == "0"))
        || ((where_item.Key == "boo") && (where_item.Value == "1"))
    )
    .ToDictionary(each_item => each_item.Key, each_item => each_item.Value);

答案 6 :(得分:0)

也许你正试图做这样的事情?

List<T> firstList;
List<T2> toBeRemovedItems;
List<T> finalList;

foreach(T item in firstList)
{
    toBeRemovedItems = CheckIfWeRemoveThisOne(item.Number, item.Id);
    if (toBeRemovedItems == null && toBeRemovedItems.Count() == 0)
        finalList.Add(item);
}

这就是我设法解决一个问题,即摆脱List<ViewModel>List<Model>之间的重复问题。我使用CheckIfWeRemoveThisOne函数来检查item.Number是否属于某个其他项目,使用ID作为定义特征。如果它找到另一个项目(重复),而不是尝试将其从原始列表中删除(我正在返回List<Model>并且首先在我的函数中获得List<ViewModel>,所以无论如何,我对如何做到这一点表示怀疑),我刚刚建立了一个新列表 - 如果发现它没有问题,将结果添加到其中。