2009-07-26 58 views
27

Bây giờ tôi đến một giai đoạn để có được tất cả các dữ liệu của tôi như là một danh sách trong bộ nhớ cache (đối tượng) và điều tiếp theo của tôi tôi phải làm là để loại bỏ một số trường hợp từ danh sách.Xóa các phiên bản khỏi danh sách bằng cách sử dụng LINQ hoặc Lambda?

Thông thường, tôi sẽ làm loại bỏ như thế này:

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 
    }); 
} 

Để cụ thể hơn, tôi thực sự xây dựng hoặc cư toBeRemvoedItems danh sách của một lớp năng động (không phải là một lớp được xác định chính thức). Ví dụ, lớp T là một cái gì đó giống như MyClass và mã để loại bỏ là:

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; 
    }); 
} 

tôi đã cố gắng để tìm kiếm Remove() phương pháp trong IEnumerable giao diện từ MSDN, nhưng tôi không thể tìm ra phương pháp Remove() đó (nó có ý nghĩa rằng IEnumerable chỉ được sử dụng để đếm). Trong lớp List, có một số phương thức quá tải Remove(...). Tôi không chắc chắn nếu có bất kỳ cách nào khác để loại bỏ các mục từ một danh sách bằng cách sử dụng LINQ hoặc Lambda biểu thức?

Nhân tiện, tôi đã nghĩ về cách thực hiện truy vấn đối với danh sách để nhận tập hợp con hoặc danh sách IEnumerable mới với Điều kiện ở đâu, tương tự như di chuyển các mục từ danh sách. Tuy nhiên, tôi thích xóa các mục khỏi danh sách được lưu trong bộ nhớ cache của tôi và có một số trường hợp tôi không thể đặt lại thuộc tính danh sách trong một lớp thành danh sách mới (ví dụ như tập hợp riêng).

+0

Trông giống như một bản dupe. Vâng, về cơ bản bạn đã đề cập đến tất cả các phương pháp có thể có trong bài đăng ... http://stackoverflow.com/questions/1120336/what-is-the-easiest-way-to-foreach-through-a-listt-removing-unwanted -objects –

Trả lời

40

Bạn có thể sử dụng phương pháp RemoveAll:

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

Tôi nghĩ rằng nó thực sự là một phương pháp của Danh sách , không phải là một phương pháp mở rộng – Jimmy

+0

Cảm ơn! Tôi cập nhật bài đăng của mình. –

+0

Việc hiểu mã của bạn là bạn xóa từng mục một. Tôi vẫn phải lặp lại từng lời giống như đề nghị của Rchard Hein. –

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

Quá trễ nữa. Oh well.

+0

Không chắc chắn nếu nó có thể vượt qua hai tham số để RemoveAll (lambda func) để loại bỏ một toBeRemovedItems, mà không thông qua vòng lặp foreach. Để chắc chắn nó đã rất dễ đọc. –

21

Bạn có thể sử dụng phương thức LINQ's Where để lọc ra các giá trị không phải là một phần của danh sách. Kết quả là IEnumerable<T> với các phần tử đã bị xóa.

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

này sẽ không được cập nhật bản gốc List<T> dụ mà thay vào đó sẽ tạo ra một mới IEnumerable<T> với các giá trị gỡ bỏ.

+0

Sự hoàn hảo là gì. nhấn làm điều này so với một vòng lặp for loại bỏ các mục? –

4

Tôi đồng ý với đề nghị của lọc ra các mục nhất định Jared, nhưng nó trông giống như một join trên Value1 sẽ là một cách tiếp cận hiệu quả hơn:

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

Cập nhật: Rõ ràng tôi không lúc đọc hiểu - cách tiếp cận mới :

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; 
}); 

Tất nhiên, sẽ tốt hơn nếu danh sách xóa của bạn có thể bắt đầu làm từ điển. Cuối cùng, chúng tôi chỉ cố gắng làm cho trận đấu của chúng tôi trên Value1 hiệu quả hơn.

+0

Tham gia có tương tự như Giao thức SQL không? hoặc truy vấn LINQ này như thế? –

+0

Dù sao, như tôi đã đề cập trong câu hỏi của tôi, nếu thuộc tính danh sách không được đặt, tôi không thể sử dụng chiến lược này. Đó là cách tốt chỉ có tôi kiểm soát danh sách. –

+0

Lưu ý - câu trả lời được cập nhật. – dahlbyk

5

Nếu tôi nhận được câu hỏi chính xác, để tạo một bộ duy nhất từ ​​hai Danh sách.

Đối với điều này, bạn có thể sử dụng sau đây

Danh sách danh sách1; Danh sách danh sách2;

Danh sách danh sách3 = list1.Ngoại trừ (list2)

Danh sách3 sẽ chứa các mục duy nhất.

+0

Đây là câu trả lời đầu tiên giải quyết mục tiêu của tôi, đó là cả hai loại bỏ và nhận được liệt kê các đối tượng phù hợp với lambda. Tuy nhiên, –

+0

Phải là cùng một loại bộ sưu tập để làm việc này. – vapcguy

1

Đối với bộ sưu tập không phải là danh sách (không thể hiển thị RemoveAll), bạn vẫn có thể xóa các mục có một lớp lót.

Để thay thế nội tuyến, chỉ cần tạo danh sách các mục cần xóa, sau đó chạy qua nó và thực thi xóa mã.

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); 
    }); 

Để thay thế bằng bản sao, chỉ cần tạo bộ lọc có thể đếm và trả lại bản sao mới.

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); 
0

Có thể bạn đang cố gắng làm điều gì đó như thế này?

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); 
} 

Đây là cách tôi quản lý để giải quyết một vấn đề với việc thoát khỏi trùng lặp giữa một List<ViewModel>List<Model>. Tôi đã sử dụng hàm CheckIfWeRemoveThisOne để kiểm tra xem item.Number có thuộc về một số mục khác không, sử dụng ID làm đặc tính xác định. Nếu nó tìm thấy một mục khác (một bản sao), thay vì thử và loại bỏ nó khỏi danh sách ban đầu (mà tôi đã nhận được một List<Model> và đã được đưa ra List<ViewModel> vào chức năng của tôi ở nơi đầu tiên, vì vậy tôi đã nghi ngờ của tôi như thế nào tôi có thể làm điều đó, dù sao), tôi chỉ cần xây dựng một danh sách mới - thêm kết quả vào nó nếu nó được tìm thấy là ok.

Các vấn đề liên quan