Case-INsensitive Dictionary với loại khóa chuỗi trong C #


155

Nếu tôi có một Dictionary<String,...>phương pháp như ContainsKeykhông phân biệt chữ hoa chữ thường?

Điều này có vẻ liên quan, nhưng tôi đã không hiểu đúng: c # Dictionary: làm cho Key không phân biệt chữ hoa chữ thường thông qua khai báo


5
Có gì sai khi sử dụng StringComparer.InvariantCultureIgnoreCase? Nó thực hiện những gì nó nói ...
leppie

5
Tôi chưa bao giờ nghe về nó, do đó câu hỏi!
Cậu bé


Câu hỏi đó có liên quan, nhưng không hoàn toàn trùng lặp với câu hỏi này. Đó là một trong những làm thế nào để đối phó với một từ điển hiện có. Tôi đang bắt đầu với mã mới, vì vậy câu trả lời ở đây phù hợp hơn.
tạm biệt

Câu trả lời:


321

Điều này có vẻ liên quan, nhưng tôi đã không hiểu đúng: c # Dictionary: làm cho Key không phân biệt chữ hoa chữ thường thông qua khai báo

Nó thực sự có liên quan. Giải pháp là yêu cầu cá thể từ điển không sử dụng phương thức so sánh chuỗi tiêu chuẩn (phân biệt chữ hoa chữ thường) mà là sử dụng một trường hợp không phân biệt chữ hoa chữ thường. Điều này được thực hiện bằng cách sử dụng hàm tạo thích hợp :

var dict = new Dictionary<string, YourClass>(
        StringComparer.InvariantCultureIgnoreCase);

Hàm tạo dự kiến ​​sẽ IEqualityComparercho từ điển biết cách so sánh các khóa.

StringComparer.InvariantCultureIgnoreCasecung cấp cho bạn một IEqualityComparerví dụ so sánh các chuỗi theo cách không phân biệt chữ hoa chữ thường.


1
Hoàn hảo, bằng cách nào đó tôi đã bỏ lỡ cách giống như STL để chuyển bộ so sánh vào ctor.
Cậu bé

7
Tôi không bao giờ hết ngạc nhiên khi tôi luôn tìm thấy câu trả lời cho bất kỳ câu hỏi mã hóa nào ở đây! Có lẽ tôi sẽ đặt tên con mèo tiếp theo của tôi theo bạn, Konrad! :-)
Jamie

10
Có thể, so sánh StringComparison.OrdinalIgnoreCase nhanh hơn so với dựa trên văn hóa: stackoverflow.com/questions/492799/ (
Manushin Igor

Làm cách nào để làm điều đó nếu tôi không tạo từ điển nhưng cố gắng sử dụng ContainsKey () cho trường hợp khóa không nhạy cảm trong trường hợp từ điển hiện có mà tôi nhận được như một phần của đối tượng?
Shridhar R Kulkarni

1
@ShridharRKulkarni Về cơ bản bạn không thể (một cách hiệu quả). Logic so sánh là một phần cốt lõi của cấu trúc dữ liệu từ điển nội bộ. Để cho phép điều này, container sẽ phải duy trì nhiều chỉ mục cho dữ liệu của nó và từ điển không làm điều này.
Konrad Rudolph

21
var myDic = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
myDic.Add("HeLlo", "hi");

if (myDic.ContainsKey("hello"))
    Console.WriteLine(myDic["hello"]);

1
Đoạn mã nói lên tất cả. Rất hữu ích. Không chắc chắn lý do tại sao bài đăng này có ít lượt upvote so với câu trả lời được chấp nhận chỉ vì trễ 3 phút.
RBT

14

Có rất ít khả năng thỏa thuận của bạn với từ điển được lấy từ bên thứ 3 hoặc dll bên ngoài. Sử dụng linq

YourDictionary.Any(i => i.KeyName.ToLower().Contains("yourstring")))


3
Điều này làm việc tuyệt vời. Mặc dù vậy, một lời cảnh báo, nếu bạn đổi Anythành SingleOrDefaultbạn sẽ không nullquay lại nếu nó không tồn tại, thay vào đó bạn sẽ nhận được một keyvaluepair với cả khóa và giá trị được đặt thành null!
NibblyPig

1
ContainsCó vẻ như một trường hợp sử dụng rất cụ thể cho một cái gì đó bạn đang làm việc tại thời điểm đó. Là một câu trả lời hữu ích chung chung hơn, tôi nghĩ Equalslà tốt hơn. Và trên cùng một lưu ý, thay vì sao chép một chuỗi với ToLower(), nó sẽ còn tốt hơn để sử dụng StringComparison.xxxCase.
Suamere

1
điều này rất hữu ích và việc loại bỏ ToLower chắc chắn là một sự cải tiến - trường hợp sử dụng của tôi là: return ApplicationBuffs.Any (b => b.Key.Equals (Name, StringComparison.OrdinalIgnoreCase)); một trường hợp không nhạy cảm hoàn hảo Chứa vào một từ điển phân biệt chữ hoa chữ thường.
David Burford

Tôi rất cám dỗ downvote này. Lời cảnh báo, nếu bạn là chủ sở hữu của từ điển thì đây chắc chắn không phải là cách để làm điều đó. Chỉ sử dụng phương pháp này nếu bạn không biết từ điển đã được khởi tạo như thế nào. Ngay cả sau đó, để khớp chính xác chuỗi (không chỉ khớp một phần), hãy sử dụng dict.Keys.Contains("bla", appropriate comparer)quá tải LINQ để dễ sử dụng.
nawfal

1

Tôi vừa gặp phải rắc rối tương tự khi tôi cần một từ điển nhạy cảm caseIN trong bộ điều khiển ASP.NET Core.

Tôi đã viết một phương pháp mở rộng mà thực hiện các mẹo. Có lẽ điều này cũng có thể hữu ích cho những người khác ...

public static IDictionary<string, TValue> ConvertToCaseInSensitive<TValue>(this IDictionary<string, TValue> dictionary)
{
    var resultDictionary = new Dictionary<string, TValue>(StringComparer.InvariantCultureIgnoreCase);
    foreach (var (key, value) in dictionary)
    {
        resultDictionary.Add(key, value);
    }

    dictionary = resultDictionary;
    return dictionary;
}

Để sử dụng phương thức mở rộng:

myDictionary.ConvertToCaseInSensitive();

Sau đó nhận được một giá trị từ từ điển với:

myDictionary.ContainsKey("TheKeyWhichIsNotCaseSensitiveAnymore!");

0

Nếu bạn không có quyền kiểm soát trong việc tạo cá thể, giả sử đối tượng của bạn bị khử từ json, v.v., bạn có thể tạo một lớp bao bọc kế thừa từ lớp từ điển.

public class CaseInSensitiveDictionary<TValue> : Dictionary<string, TValue>
{
    public CaseInSensitiveDictionary() : base(StringComparer.OrdinalIgnoreCase){}
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.