2009-07-24 65 views
169

Ở đây tôi có một ví dụ đơn giản để tìm một mục trong danh sách các chuỗi. Thông thường tôi sử dụng cho vòng lặp hoặc đại biểu ẩn danh để thực hiện việc này như sau:Tìm một mục trong Danh sách bằng LINQ?

int GetItemIndex(string search) 
{ 
    int found = -1; 
    if (_list != null) 
    { 
    foreach (string item in _list) // _list is an instance of List<string> 
    { 
     found++; 
     if (string.Equals(search, item)) 
     { 
      break; 
     } 
     } 
     /* use anonymous delegate 
     string foundItem = _list.Find(delegate(string item) { 
     found++; 
     return string.Equals(search, item); 
     }); 
     */ 
    } 
    return found; 
} 

LINQ mới cho tôi. Tôi tò mò nếu tôi có thể sử dụng LINQ để tìm mục trong danh sách? Làm thế nào nếu có thể?

+0

Đó là tuyệt vời. Tuy nhiên, đó là tất cả các phong cách biểu thức lamda. Tôi sử dụng một danh sách đơn giản ở đây. Danh sách có thể là một lớp với nhiều thuộc tính và một số được sử dụng để tìm kiếm. Vì vậy, bất kỳ cách nào LINQ để tìm kiếm như "từ .. trong ... nơi ... chọn ..." –

+0

Không, xin lỗi. Hầu hết các phương thức này (Đầu tiên, Đơn, Bất kỳ, ...) không thể được * trực tiếp * được dịch sang biểu mẫu đó. –

+0

Nevermind, thực sự bạn có thể loại bỏ lambdas trong một vài trường hợp ... –

Trả lời

364

Có một vài cách (lưu ý đây là không phải danh sách đầy đủ).

1) Single sẽ trả về một kết quả duy nhất, nhưng sẽ ném một ngoại lệ nếu nó tìm thấy none hoặc nhiều hơn một (mà có thể hoặc không thể là những gì bạn muốn):

string search = "lookforme"; 
List<string> myList = new List<string>(); 
string result = myList.Single(s => s == search); 

Note SingleOrDefault() sẽ hành xử tương tự, ngoại trừ nó sẽ trả về null cho các kiểu tham chiếu, hoặc giá trị mặc định cho các kiểu giá trị, thay vì ném một ngoại lệ.

2) Where sẽ trở lại tất cả các mục mà phù hợp với tiêu chí của bạn, vì vậy bạn có thể nhận được một IEnumerable với một phần tử:

IEnumerable<string> results = myList.Where(s => s == search); 

3) First sẽ trở lại mục đầu tiên mà phù hợp với tiêu chí của bạn:

string result = myList.First(s => s == search); 

Lưu ý FirstOrDefault() sẽ hoạt động giống nhau, ngoại trừ nó sẽ trả về giá trị mặc định cho giá trị tham chiếu hoặc giá trị mặc định cho loại giá trị thay vì ném ngoại lệ.

+30

Câu trả lời hay.Tôi tìm thấy SingleOrDefault là câu trả lời của tôi về sự lựa chọn - giống như Single nhưng trả về 'null' nếu nó không thể tìm thấy nó. –

+2

Tôi không biết hoặc là Single() hoặc SingleOrDefault(). Rất hữu dụng. – draconis

+0

Các phương pháp này có thể được sử dụng với các bộ sưu tập khác như 'ReadOnlyCollection' hoặc' ObservableCollection' không? – yellavon

65

Nếu bạn muốn chỉ số của nguyên tố này, điều này sẽ làm điều đó:

int index = list.Select((item, i) => new { Item = item, Index = i }) 
       .First(x => x.Item == search).Index; 

// or 
var tagged = list.Select((item, i) => new { Item = item, Index = i }); 
int index = (from pair in tagged 
      where pair.Item == search 
      select pair.Index).First(); 

Bạn không thể thoát khỏi những lambda trong đèo đầu tiên.

Lưu ý rằng điều này sẽ ném nếu mục không tồn tại. Điều này giải quyết vấn đề bằng cách phải dùng đến ints nullable:

var tagged = list.Select((item, i) => new { Item = item, Index = (int?)i }); 
int? index = (from pair in tagged 
      where pair.Item == search 
      select pair.Index).FirstOrDefault(); 

Nếu bạn muốn mục:

// Throws if not found 
var item = list.First(item => item == search); 
// or 
var item = (from item in list 
      where item == search 
      select item).First(); 

// Null if not found 
var item = list.FirstOrDefault(item => item == search); 
// or 
var item = (from item in list 
      where item == search 
      select item).FirstOrDefault(); 

Nếu bạn muốn đếm số lượng các mục phù hợp:

int count = list.Count(item => item == search); 
// or 
int count = (from item in list 
      where item == search 
      select item).Count(); 

Nếu bạn muốn tất cả các mục phù hợp:

var items = list.Where(item => item == search); 
// or 
var items = from item in list 
      where item == search 
      select item; 

Và đừng quên kiểm tra danh sách cho null trong bất kỳ trường hợp nào trong số này.

Hoặc sử dụng (list ?? Enumerable.Empty<string>()) thay vì list.

Cảm ơn Pavel đã giúp đỡ trong các nhận xét.

+2

Hai điểm. Đầu tiên, không cần phải sử dụng 'string.Equals' ở đây - không có gì sai với' == '. Thứ hai, tôi cũng đề cập đến 'FirstOrDefault' (đối với các trường hợp có thể không có), và' Select' với chỉ số để bao gồm trường hợp chỉ mục mục cần thiết (vì nó nằm trong mẫu trong câu hỏi). –

+0

Cảm ơn bạn đã chỉ ra những điều đó. –

+0

Tôi chưa hài lòng. Không có chỉ mục -1 (không tìm thấy) trong ví dụ của tôi. Bất kì lời đề nghị nào? –

12

Nếu nó thực sự là một List<string> bạn không cần LINQ, chỉ cần sử dụng:

int GetItemIndex(string search) 
{ 
    return _list == null ? -1 : _list.IndexOf(search); 
} 

Nếu bạn đang tìm kiếm mục riêng của mình, hãy thử:

string GetItem(string search) 
{ 
    return _list == null ? null : _list.FirstOrDefault(s => s.Equals(search)); 
} 
+1

Theo logic của ví dụ đầu tiên, chúng ta có thể sử dụng '_list.Find (search)' cho lần thứ hai. – jwg

9

Bạn có muốn mục trong danh sách hoặc bản thân mục thực tế (sẽ giả định chính mục đó).

Dưới đây là một loạt các tùy chọn cho bạn:

string result = _list.First(s => s == search); 

string result = (from s in _list 
       where s == search 
       select s).Single(); 

string result = _list.Find(search); 

int result = _list.IndexOf(search); 
+0

Whoa ... một số người siêu nhanh một trong những kích hoạt;) – Kelsey

+0

làm thế nào về chỉ số như là một giá trị trả lại? –

+0

và tôi có cần kiểm tra xem danh sách _list có rỗng không trong dạng từ .. trong _list ...? –

2

Tôi đã từng sử dụng một từ điển đó là một số loại một danh sách được lập chỉ mục trong đó sẽ cho tôi một cách chính xác những gì tôi muốn khi tôi muốn nó.

Dictionary<string, int> margins = new Dictionary<string, int>(); 
margins.Add("left", 10); 
margins.Add("right", 10); 
margins.Add("top", 20); 
margins.Add("bottom", 30); 

Bất cứ khi nào tôi muốn truy cập lề giá trị của tôi, ví dụ, tôi giải quyết từ điển của tôi:

int xStartPos = margins["left"]; 
int xLimitPos = margins["right"]; 
int yStartPos = margins["top"]; 
int yLimitPos = margins["bottom"]; 

Vì vậy, tùy thuộc vào những gì bạn đang làm, một cuốn từ điển có thể hữu ích.

+0

Câu trả lời hay cho câu hỏi khác. – jwg

6

Phương pháp này là dễ dàng hơn và an toàn hơn

var lOrders = new List<string>(); 

bool insertOrderNew = lOrders.Find(r => r == "1234") == null ? true : false

+1

Tôi nghĩ rằng chúng ta thậm chí không cần 'true: false' dưới đây sẽ hoạt động giống nhau 'bool insertOrderNew = lOrders.Find (r => r ==" 1234 ") == null;' – Vbp

5

Làm thế nào về IndexOf?

kiếm cho các đối tượng quy định và trả về chỉ số của sự xuất hiện đầu tiên trong danh sách

Ví dụ

> var boys = new List<string>{"Harry", "Ron", "Neville"}; 
> boys.IndexOf("Neville") 
2 
> boys[2] == "Neville" 
True 

Lưu ý rằng nó sẽ trả về -1 nếu giá trị không xảy ra trong danh sách

> boys.IndexOf("Hermione") 
-1 
2

Đây là một cách để viết lại phương pháp của bạn để sử dụng L INQ:

public static int GetItemIndex(string search) 
{ 
    List<string> _list = new List<string>() { "one", "two", "three" }; 

    var result = _list.Select((Value, Index) => new { Value, Index }) 
      .SingleOrDefault(l => l.Value == search); 

    return result == null ? -1 : result.Index; 
} 

Như vậy, gọi nó với

GetItemIndex("two") sẽ trở lại 1,

GetItemIndex("notthere") sẽ trở lại -1.

tham khảo: linqsamples.com

1

Hãy thử mã này:

return context.EntitytableName.AsEnumerable().Find(p => p.LoginID.Equals(loginID) && p.Password.Equals(password)).Select(p => new ModelTableName{ FirstName = p.FirstName, UserID = p.UserID }); 
1

này sẽ giúp bạn trong việc có được giá trị đầu tiên hoặc mặc định trong tìm kiếm LINQ Danh sách bạn

var results = _List.Where(item => item == search).FirstOrDefault(); 

tìm kiếm này sẽ tìm ra giá trị đầu tiên hoặc giá trị mặc định sẽ trả về.

1

Nếu cần tìm phần tử trong danh sách, chúng tôi có thể sử dụng phương pháp mở rộng FindFindAll nhưng có sự khác biệt nhỏ giữa chúng. Đây là một ví dụ.

List<int> items = new List<int>() { 10, 9, 8, 4, 8, 7, 8 }; 

    // It will return only one 8 as Find returns only the first occurrence of matched elements. 
    var result = items.Find(ls => ls == 8);  
// this will returns three {8,8,8} as FindAll returns all the matched elements. 
     var result1 = items.FindAll(ls => ls == 8); 
0

Bạn muốn tìm kiếm một đối tượng trong danh sách đối tượng.

Điều này sẽ giúp bạn nhận được giá trị đầu tiên hoặc giá trị mặc định trong tìm kiếm Danh sách Linq của bạn.

var item = list.FirstOrDefault(items => items.Reference == ent.BackToBackExternalReferenceId); 

hoặc

var item = (from items in list 
    where items.Reference == ent.BackToBackExternalReferenceId 
    select items).FirstOrDefault(); 
Các vấn đề liên quan