พจนานุกรมตัวพิมพ์เล็กและตัวพิมพ์ใหญ่พร้อมสตริงของคีย์ใน C #


156

ถ้าฉันมีDictionary<String,...>มันเป็นไปได้ที่จะทำวิธีการเช่นContainsKeyกรณีตาย?

ดูเหมือนจะเกี่ยวข้องกัน แต่ฉันไม่เข้าใจอย่างถูกต้อง: c # Dictionary: การทำให้ตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ผ่านการประกาศ


6
มีอะไรผิดปกติกับการใช้งานStringComparer.InvariantCultureIgnoreCase? มันทำในสิ่งที่มันบอกว่า ...
leppie

5
ฉันไม่เคยได้ยินเรื่องนี้เลยดังนั้นคำถาม!
นายบอย


คำถามนั้นเกี่ยวข้อง แต่ไม่ซ้ำกับคำถามนี้ สิ่งนั้นจะเข้าสู่วิธีจัดการกับพจนานุกรมที่มีอยู่ ฉันเริ่มด้วยรหัสใหม่ดังนั้นคำตอบที่นี่เหมาะสมกว่า
กู๊ดอาย

คำตอบ:


322

ดูเหมือนจะเกี่ยวข้องกัน แต่ฉันไม่เข้าใจอย่างถูกต้อง: c # Dictionary: การทำให้ตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ผ่านการประกาศ

มันเกี่ยวข้องกันอย่างแน่นอน การแก้ปัญหาคือบอกอินสแตนซ์ของพจนานุกรมไม่ให้ใช้วิธีเปรียบเทียบสตริงมาตรฐาน (ซึ่งต้องตรงตามตัวพิมพ์ใหญ่และตัวพิมพ์เล็ก) แต่ใช้ตัวพิมพ์เล็กและตัวพิมพ์เล็ก สิ่งนี้ทำโดยใช้Constructor ที่เหมาะสม :

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

ตัวสร้างคาดว่าIEqualityComparerอันไหนที่บอกพจนานุกรมถึงวิธีการเปรียบเทียบกุญแจ

StringComparer.InvariantCultureIgnoreCaseให้IEqualityComparerอินสแตนซ์ที่เปรียบเทียบสตริงในลักษณะที่ไม่สนใจขนาดตัวพิมพ์


1
สมบูรณ์แบบฉันพลาดวิธีที่เหมือน STL ในการส่งตัวเปรียบเทียบไปยัง ctor
นายบอย

7
ไม่เคยทำให้ฉันประหลาดใจเลยว่าฉันจะหาคำตอบของคำถามการเข้ารหัสได้ที่นี่! บางทีฉันอาจจะตั้งชื่อแมวตัวต่อไปของฉันตามคุณคอนราด! :-)
Jamie

10
เป็นไปได้การเปรียบเทียบ StringComparison.OrdinalIgnoreCase เร็วกว่าตามวัฒนธรรม: stackoverflow.com/questions/492799/ …
Manushin Igor

ฉันจะทำอย่างไรถ้าฉันไม่ได้สร้างพจนานุกรม แต่พยายามใช้ containKey () สำหรับคีย์ที่ไม่ตรงตามตัวพิมพ์เล็กและใหญ่กับพจนานุกรมที่มีอยู่ที่ฉันได้รับเป็นส่วนหนึ่งของวัตถุ
Shridhar R Kulkarni

1
@ShridharRKulkarni คุณพื้นฐานไม่สามารถ (มีประสิทธิภาพ) ตรรกะการเปรียบเทียบเป็นส่วนหลักของโครงสร้างข้อมูลพจนานุกรมภายใน หากต้องการอนุญาตสิ่งนี้ภาชนะจะต้องเก็บรักษาดัชนีไว้หลายดัชนีสำหรับข้อมูลและพจนานุกรมจะไม่ทำเช่นนี้
Konrad Rudolph

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

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

1
ข้อมูลโค้ดบอกทุกอย่าง มีประโยชน์มาก ไม่แน่ใจว่าทำไมโพสต์นี้มี upvotes น้อยมากเมื่อเทียบกับคำตอบที่ยอมรับเพียงแค่มาสาย 3 นาที
RBT

14

มีโอกาสน้อยที่การจัดการกับพจนานุกรมของคุณจะถูกดึงจากบุคคลที่สามหรือ dll ภายนอก ใช้ linq

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


3
มันใช้งานได้ดี คำเตือน แต่ถ้าคุณเปลี่ยนAnyไปSingleOrDefaultคุณจะไม่ได้รับnullกลับถ้ามันไม่ได้อยู่แทนคุณจะได้รับ KeyValuePair มีทั้งที่สำคัญและตั้งค่าให้เป็นnull!
NibblyPig

1
Containsดูเหมือนว่าจะเป็นกรณีใช้งานที่เฉพาะเจาะจงกับสิ่งที่คุณกำลังทำอยู่ในขณะนั้น ในฐานะที่เป็นคำตอบที่เป็นประโยชน์โดยทั่วไปฉันคิดว่าEqualsดีกว่า และเมื่อทราบเหมือนกันว่าแทนที่จะทำซ้ำสตริงกับมันจะดียิ่งขึ้นกับการใช้งานToLower() StringComparison.xxxCase
Suamere

1
สิ่งนี้มีประโยชน์มากและการกำจัด ToLower เป็นการปรับปรุงอย่างแน่นอน - กรณีการใช้งานของฉันคือ: ส่งคืน AppliedBuffs.Any (b => b.Key.Equals (ชื่อ StringComparison.OrdinalIgnoreCase)); case-insensitive ที่สมบูรณ์แบบประกอบด้วยในพจนานุกรมที่เล็กและใหญ่
David Burford

ฉันถูกล่อลวงลงคะแนนเสียงเช่นนี้ คำเตือนถ้าคุณเป็นเจ้าของพจนานุกรมนี่ไม่ใช่วิธีที่จะทำ ใช้วิธีการนี้เฉพาะในกรณีที่คุณไม่ทราบว่าพจนานุกรมมีการสร้างอินสแตนซ์ได้อย่างไร แม้สำหรับสตริงที่ตรงกัน (ไม่ใช่แค่ส่วนที่ตรงกัน) ให้ใช้dict.Keys.Contains("bla", appropriate comparer)LINQ โอเวอร์โหลดเพื่อความสะดวกในการใช้งาน
nawfal

1

ฉันพบปัญหาแบบเดียวกับที่ฉันต้องการพจนานุกรม caseINSitive ในตัวควบคุม ASP.NET Core

ฉันเขียนวิธีการต่อซึ่งทำเคล็ดลับ บางทีนี่อาจเป็นประโยชน์สำหรับผู้อื่นเช่นกัน ...

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

วิธีใช้ส่วนขยาย:

myDictionary.ConvertToCaseInSensitive();

จากนั้นรับค่าจากพจนานุกรมด้วย:

myDictionary.ContainsKey("TheKeyWhichIsNotCaseSensitiveAnymore!");

0

หากคุณไม่มีการควบคุมในการสร้างอินสแตนซ์สมมติว่าวัตถุของคุณถูก desterilized จาก json ฯลฯ คุณสามารถสร้างคลาส wrapper ที่สืบทอดมาจากคลาสพจนานุกรม

public class CaseInSensitiveDictionary<TValue> : Dictionary<string, TValue>
{
    public CaseInSensitiveDictionary() : base(StringComparer.OrdinalIgnoreCase){}
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.