2010-10-16 43 views
75

Tôi có một danh sách testList có chứa một chuỗi các chuỗi. Tôi muốn thêm một chuỗi mới vào số testList chỉ khi nó chưa tồn tại trong danh sách. Do đó, tôi cần phải thực hiện tìm kiếm không phân biệt chữ hoa chữ thường và làm cho nó hiệu quả. Tôi không thể sử dụng Contains vì điều đó không tính đến vỏ bọc. Tôi cũng không muốn sử dụng ToUpper/ToLower vì lý do hiệu suất. Tôi đã xem qua phương pháp này, hoạt động:Tìm kiếm danh sách phân biệt chữ hoa chữ thường

if(testList.FindAll(x => x.IndexOf(keyword, 
         StringComparison.OrdinalIgnoreCase) >= 0).Count > 0) 
     Console.WriteLine("Found in list"); 

Tác phẩm này, nhưng cũng phù hợp với từng phần. Nếu danh sách chứa "dê", tôi không thể thêm "yến mạch" vì nó tuyên bố rằng "yến mạch" đã có trong danh sách. Có cách nào để tìm kiếm danh sách hiệu quả theo cách không phân biệt chữ hoa chữ thường, từ nào phải khớp chính xác không? cảm ơn

Trả lời

105

Thay vì String.IndexOf, hãy sử dụng String.Equals để đảm bảo bạn không có kết quả khớp một phần. Ngoài ra, đừng sử dụng FindAll khi nó đi qua mọi phần tử, sử dụng FindIndex (nó dừng trên phần tử đầu tiên nó chạm).

if(testList.FindIndex(x => x.Equals(keyword, 
    StringComparison.OrdinalIgnoreCase)) != -1) 
    Console.WriteLine("Found in list"); 

Cách khác sử dụng một số phương pháp LINQ (mà cũng dừng lại trên người đầu tiên nó chạm)

if(testList.Any(s => s.Equals(keyword, StringComparison.OrdinalIgnoreCase))) 
    Console.WriteLine("found in list"); 
+0

Chỉ cần thêm, trong một vài xét nghiệm nhanh chóng, dường như phương pháp đầu tiên là nhanh hơn khoảng 50%. Có thể ai đó khác có thể xác nhận/phủ nhận điều đó. – Brap

+4

Kể từ .NET 2.0, điều này bây giờ dễ dàng thực hiện - xem câu trả lời của shaxby bên dưới. – Joe

+3

Tham chiếu của phương thức Chứa phương pháp shaxby (có một tình trạng quá tải chiếm IEqualityComparer) là một phần của LINQ, vì vậy chắc chắn nó không có sẵn từ .NET 2.0. Chỉ có lớp StringComparer đã được khoảng một thời gian. Danh sách không có phương pháp đó, cũng không ArrayList hoặc StringCollection (những thứ mà ông có thể dễ dàng được tham chiếu như là 'danh sách' của mình). –

0

Bạn đang kiểm tra nếu kết quả của IndexOf là lớn hơn hoặc bằng 0, có nghĩa là dù trận đấu bắt đầu ở bất kỳ nơi nào trong chuỗi. Hãy thử kiểm tra nếu nó bằng-0:

if (testList.FindAll(x => x.IndexOf(keyword, 
        StringComparison.OrdinalIgnoreCase) >= 0).Count > 0) 
    Console.WriteLine("Found in list"); 

Now "dê" và "yến mạch" sẽ không phù hợp, nhưng "con dê" và "goa" ý chí. Để tránh điều này, bạn có thể so sánh các lenghts của hai chuỗi.

Để tránh tất cả các biến chứng này, bạn có thể sử dụng từ điển thay vì danh sách. Chúng chính là chuỗi chữ thường và giá trị sẽ là chuỗi thực. Bằng cách này, hiệu suất không bị tổn thương vì bạn không phải sử dụng ToLower cho mỗi so sánh, nhưng bạn vẫn có thể sử dụng Contains.

11

Dựa trên Adam Sills câu trả lời ở trên - đây là một phương pháp mở rộng sạch đẹp cho Có ... :)

///---------------------------------------------------------------------- 
/// <summary> 
/// Determines whether the specified list contains the matching string value 
/// </summary> 
/// <param name="list">The list.</param> 
/// <param name="value">The value to match.</param> 
/// <param name="ignoreCase">if set to <c>true</c> the case is ignored.</param> 
/// <returns> 
/// <c>true</c> if the specified list contais the matching string; otherwise, <c>false</c>. 
/// </returns> 
///---------------------------------------------------------------------- 
public static bool Contains(this List<string> list, string value, bool ignoreCase = false) 
{ 
    return ignoreCase ? 
     list.Any(s => s.Equals(value, StringComparison.OrdinalIgnoreCase)) : 
     list.Contains(value); 
} 
0

Tôi đã có một vấn đề tương tự, tôi cần chỉ số của mặt hàng đó nhưng nó phải là trường hợp không nhạy cảm, tôi nhìn quanh trên web cho một vài phút và thấy không có gì, vì vậy tôi chỉ viết một phương pháp nhỏ để làm cho nó thực hiện, đây là những gì tôi đã làm:

private static int getCaseInvariantIndex(List<string> ItemsList, string searchItem) 
{ 
    List<string> lowercaselist = new List<string>(); 

    foreach (string item in ItemsList) 
    { 
     lowercaselist.Add(item.ToLower()); 
    } 

    return lowercaselist.IndexOf(searchItem.ToLower()); 
} 

Thêm mã này vào cùng một tập tin, và cuộc gọi nó như sau:

int index = getCaseInvariantIndexFromList(ListOfItems, itemToFind); 

Hy vọng điều này sẽ giúp, chúc bạn may mắn!

+0

tại sao lại tạo danh sách thứ hai? Điều đó không hiệu quả lắm. for (var i = 0; i wesm

+0

Tôi đoán chúng ta sẽ không bao giờ biết. – Denny

204

Tôi nhận ra đây là một bài cũ, nhưng chỉ trong trường hợp bất cứ ai khác đang tìm kiếm, bạn thể sử dụng Contains bằng cách cung cấp các case insensitive comparer bình đẳng chuỗi như vậy:

if (testList.Contains(keyword, StringComparer.OrdinalIgnoreCase)) 
{ 
    Console.WriteLine("Keyword Exists"); 
} 

này đã có sẵn từ .net 2.0 theo msdn.

+17

Chắc chắn câu trả lời hay nhất ở đây. :) – Joe

+18

Enumerable .Contains (những gì bạn đang tham khảo) đã không được xung quanh kể từ .NET 2.0. Không có Danh sách .Có chứa quá tải bạn đang sử dụng. –

+0

@AdamSills đúng. Không có phương thức nào chứa trong Danh sách . Và nếu đó là một bộ sưu tập lười biếng, hơn nó có thể lặp lại nó một vài lần như khác Enumerable phương pháp làm. Imho, phương pháp này không nên được sử dụng cho các trường hợp như vậy, vì nó không hợp lý cho trường hợp đó. –

0

Dựa trên Lance Larsen câu trả lời - đây là một phương pháp khuyến nông với string.Compare đề nghị thay vì string.Equals

Nó là rất khuyến khích bạn sử dụng một quá tải của String.Compare mà phải mất một tham số StringComparison. Không chỉ thực hiện các quá tải này cho phép bạn xác định hành vi so sánh chính xác mà bạn dự định, việc sử dụng chúng cũng sẽ làm cho mã của bạn dễ đọc hơn đối với các nhà phát triển khác. [Josh Free @ BCL Team Blog]

public static bool Contains(this List<string> source, string toCheck, StringComparison comp) 
{ 
    return 
     source != null && 
     !string.IsNullOrEmpty(toCheck) && 
     source.Any(x => string.Compare(x, toCheck, comp) == 0); 
} 
Các vấn đề liên quan