จะเกิดอะไรขึ้นกับ C # Dictionary <int, int> lookup ถ้าไม่มีคีย์


121

ฉันพยายามตรวจสอบค่าว่าง แต่คอมไพเลอร์เตือนว่าเงื่อนไขนี้จะไม่เกิดขึ้น ฉันควรมองหาอะไร

คำตอบ:


196

สมมติว่าคุณต้องการที่จะได้รับค่าถ้าคีย์จะมีอยู่ใช้Dictionary<TKey, TValue>.TryGetValue:

int value;
if (dictionary.TryGetValue(key, out value))
{
    // Key was in dictionary; "value" contains corresponding value
} 
else 
{
    // Key wasn't in dictionary; "value" is now 0
}

(ใช้ContainsKeyแล้วตัวสร้างดัชนีทำให้มันดูคีย์ขึ้นสองครั้งซึ่งค่อนข้างไม่มีจุดหมาย)

โปรดทราบว่าแม้ว่าคุณจะใช้ประเภทการอ้างอิงการตรวจสอบค่าว่างจะไม่ทำงาน - ตัวสร้างดัชนีDictionary<,>จะให้ข้อยกเว้นหากคุณขอคีย์ที่หายไปแทนที่จะส่งคืนค่าว่าง (นี่คือความแตกต่างอย่างมากระหว่างDictionary<,>และHashtable)


@JonSkeet ไม่ใช่ TryGetValue ทำการค้นหาซ้ำด้วย ( ตามที่ระบุไว้ในเนื้อหาคำถามนี้ )?
nawfal

5
@nawfal: ฉันไม่เห็นข้อบ่งชี้ว่าคำถามนั้นระบุเลย มันบอกว่ามันทำงานได้มากกว่าContainsKeyซึ่งก็จริงเพราะมันต้องดึงค่าออกมาเช่นกัน มันไม่ได้ทำการค้นหาสองครั้ง
Jon Skeet

ฉันหวังว่าจะเป็นโมฆะ แต่สำหรับ Dictionary <TKey, enum> สิ่งนี้จะคืนค่าเท่ากับ "0" ใน enum
Jess

23

พจนานุกรมจะแสดงKeyNotFoundข้อยกเว้นในกรณีที่พจนานุกรมไม่มีคีย์ของคุณ

ตามที่แนะนำContainsKeyคือข้อควรระวังที่เหมาะสม TryGetValueยังมีประสิทธิภาพ

สิ่งนี้ช่วยให้พจนานุกรมสามารถจัดเก็บค่าว่างได้อย่างมีประสิทธิภาพมากขึ้น หากไม่มีการทำงานในลักษณะนี้การตรวจสอบผลลัพธ์ที่เป็นโมฆะจากตัวดำเนินการ [] จะบ่งชี้ว่าเป็นค่าว่างหรือการไม่มีอยู่ของคีย์อินพุตซึ่งไม่เป็นผลดี


สามารถดูข้อมูลเพิ่มเติมได้ที่ MSDN: msdn.microsoft.com/en-gb/library/9tee9ht2.aspx
cyberzed

10

หากคุณเพิ่งตรวจสอบก่อนที่จะพยายามเพิ่มค่าใหม่ให้ใช้ContainsKeyวิธีการ:

if (!openWith.ContainsKey("ht"))
{
    openWith.Add("ht", "hypertrm.exe");
}

หากคุณกำลังตรวจสอบว่ามีค่าอยู่ให้ใช้TryGetValueวิธีการตามที่อธิบายไว้ในคำตอบของ Jon Skeet


8
TryGet ดีกว่า
Ruben Bartelink

2
เพราะคุณกำลังแก้ไขการค้นหาคีย์ผ่านแฮชแท็กสองครั้งหากคุณได้รับทันทีหลังจากมี Wintellect PowerCollections ยังมีGetValueElseAddวิธีการที่คุณให้ค่า (หรือ a Func<TValue>) เพื่อบันทึกความละเอียดในส่วนแทรกหากคุณจะเพิ่มหากไม่มี ฉันเดาว่าสาเหตุที่ไม่ได้ทำให้มันกลายเป็น. NET libs เป็นเพราะ Add path นั้นไม่บ่อยถ้าคุณใช้มันในรูปแบบแคช]
Ruben Bartelink

@rub: ฉันเดาว่าขึ้นอยู่กับวัตถุประสงค์ของรหัส หากคุณต้องการใช้ค่าที่ฉันยอมรับว่าTryGetValueจะดีกว่า แต่ถ้าคุณต้องการตรวจสอบว่าพจนานุกรมมีคีย์หรือไม่เพื่อหลีกเลี่ยงการเพิ่มซ้ำฉันจะบอกว่าContainsKeyดีพอ ๆ กัน (ถ้าไม่ดีกว่า)
Fredrik Mörk

@Fredrik: ถ้าคุณเพียงต้องการที่จะทำการตรวจสอบการบรรจุแล้วใช่มันคุ้มค่าใช้ ContainsKey โปรดทราบว่าไม่ใช่กรณีนี้ในโค้ดตัวอย่างของคำตอบนี้
Jon Skeet

@ จอน: จริงฉันพลาดจริง ๆ ที่มีการดึงมูลค่าเพิ่มทันทีหลังจากเพิ่ม
Fredrik Mörk

3

คุณควรตรวจสอบ Dictionary.ContainsKey (คีย์ int) ก่อนที่จะพยายามดึงค่าออกมา

Dictionary<int, int> myDictionary = new Dictionary<int, int>();
myDictionary.Add(2,4);
myDictionary.Add(3,5);

int keyToFind = 7;
if(myDictionary.ContainsKey(keyToFind))
{
    myValueLookup = myDictionay[keyToFind];
    // do work...
}
else
{
    // the key doesn't exist.
}

2
ทำไมคุณถึงต้องการให้มันทำการค้นหาสองครั้ง?
Jon Skeet

2
@mookid: ไม่ได้อยู่ในความคิดของฉัน แนวคิดคือพยายามค้นหากุญแจและดำเนินการตามแนวทางหนึ่งหากพบและแนวทางปฏิบัติอื่นใช่ไหม
Jon Skeet

3
@ จอน - พูดตรงๆ? เพราะไม่รู้เรื่องTryGetValue. โชคดีที่ฉันทำตอนนี้ดังนั้นฉันจะรู้ในอนาคต ฉันจะปล่อยให้คำตอบนี้เหมือนเดิมแม้ว่า 'การสนทนาจะมีค่า
ZombieSheep

@ จอนสเก็ต - ทำไมฉันถึงมาที่นี่ :)
ZombieSheep

@JonSkeet เนื่องจากก่อน C # 7 คุณไม่สามารถใช้TryGetValueในนิพจน์แลมบ์ดาได้ แม้ว่านั่นจะทำให้ฉันคิดว่าส่วนขยายใหม่ของ C # น่าจะเป็นcatchตัวดำเนินการที่คล้ายกับnullตัวดำเนินการรวมกัน
NetMage

1

คลาสผู้ช่วยมีประโยชน์:

public static class DictionaryHelper
{
    public static TVal Get<TKey, TVal>(this Dictionary<TKey, TVal> dictionary, TKey key, TVal defaultVal = default(TVal))
    {
        TVal val;
        if( dictionary.TryGetValue(key, out val) )
        {
            return val;
        }
        return defaultVal;
    }
}

บางครั้งฉันก็สงสัยว่าเหตุใดจึงไม่เพิ่มสิ่งนี้ในไลบรารีมาตรฐาน เกือบทุกภาษาที่ใช้แฮชแมปจะส่งคืนค่า null หากไม่มีรายการไม่ใช่ข้อยกเว้นที่ผิดปกติ รายการที่ไม่มีอยู่ในพจนานุกรมของคุณไม่ใช่พฤติกรรมพิเศษ
Adam Hess

@AdamHess - นั่นคือเหตุผลที่คุณมี Hashtable () ใน c # ... โชคไม่ดีที่กุญแจของคุณถูกบรรจุไว้ที่นั่น ... :(
veljkoz

0

มีคีย์คือสิ่งที่คุณกำลังมองหา


0

คุณควรใช้:

if(myDictionary.ContainsKey(someInt))
{
  // do something
}

สาเหตุที่คุณไม่สามารถตรวจสอบค่าว่างได้ก็คือคีย์ในที่นี้คือประเภทค่า


1
ประเภทของค่าค่อนข้างไม่เกี่ยวข้องเนื่องจากการตรวจสอบค่าว่างจะไม่มีผลตามที่ต้องการ
Jon Skeet

@ โจฮันเนสวิธีแก้ปัญหาของจอนเป็นวิธีที่ดีกว่าแน่นอน แต่ผู้ถามระบุว่าเขาตรวจสอบว่ามีคีย์อยู่หรือไม่และเป็น Dictionary <int, int> ดังนั้นคีย์จึงเป็นประเภทค่าที่นี่ด้วย
Razzie

0
int result= YourDictionaryName.TryGetValue(key, out int value) ? YourDictionaryName[key] : 0;

หากคีย์มีอยู่ในพจนานุกรมจะส่งคืนค่าของคีย์มิฉะนั้นจะส่งกลับ 0

หวังว่ารหัสนี้จะช่วยคุณได้


1
หากมีคีย์อยู่รหัสนี้จะค้นหาสองครั้ง TryGetValueก็เพียงพอแล้วให้ใช้valueแทนresult
Mathieu VIALES

0

พิจารณาตัวเลือกในการห่อหุ้มพจนานุกรมนี้และระบุวิธีการคืนค่าสำหรับคีย์นั้น:

public static class NumbersAdapter
{
    private static readonly Dictionary<string, string> Mapping = new Dictionary<string, string>
    {
        ["1"] = "One",
        ["2"] = "Two",
        ["3"] = "Three"
    };

    public static string GetValue(string key)
    {
        return Mapping.ContainsKey(key) ? Mapping[key] : key;
    }
}

จากนั้นคุณสามารถจัดการพฤติกรรมของพจนานุกรมนี้ได้

ตัวอย่างเช่นที่นี่: หากพจนานุกรมไม่มีคีย์จะส่งคืนคีย์ที่คุณส่งผ่านพารามิเตอร์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.