วิธีต่างๆในการเพิ่มลงในพจนานุกรม


110

อะไรคือความแตกต่างในDictionary.add(key, value)และDictionary[key] = value?

ฉันสังเกตเห็นว่าเวอร์ชันล่าสุดไม่โยนArgumentExceptionเมื่อใส่คีย์ที่ซ้ำกัน แต่มีเหตุผลใดที่จะชอบเวอร์ชันแรก?

แก้ไข : ใครมีแหล่งข้อมูลที่เชื่อถือได้เกี่ยวกับเรื่องนี้หรือไม่? ฉันได้ลอง MSDN แล้ว แต่มันก็เหมือนกับการไล่ล่าห่านป่า :(

คำตอบ:


112

ประสิทธิภาพเกือบจะเหมือนกัน 100% คุณสามารถตรวจสอบสิ่งนี้ได้โดยเปิดคลาสใน Reflector.net

นี่คือตัวสร้างดัชนีนี้:

public TValue this[TKey key]
{
    get
    {
        int index = this.FindEntry(key);
        if (index >= 0)
        {
            return this.entries[index].value;
        }
        ThrowHelper.ThrowKeyNotFoundException();
        return default(TValue);
    }
    set
    {
        this.Insert(key, value, false);
    }
}

และนี่คือวิธีการเพิ่ม:

public void Add(TKey key, TValue value)
{
    this.Insert(key, value, true);
}

ฉันจะไม่โพสต์วิธีการแทรกทั้งหมดเนื่องจากมันค่อนข้างยาวอย่างไรก็ตามวิธีการประกาศมีดังนี้:

private void Insert(TKey key, TValue value, bool add)

และยิ่งไปกว่านั้นในฟังก์ชั่นสิ่งนี้จะเกิดขึ้น:

if ((this.entries[i].hashCode == num) && this.comparer.Equals(this.entries[i].key, key))
{
    if (add)
    {
        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
    }

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

ดังนั้นสำหรับทุกวัตถุประสงค์และความตั้งใจประสิทธิภาพจะเหมือนกัน

เช่นเดียวกับการกล่าวถึงอื่น ๆ ทั้งหมดเกี่ยวกับว่าคุณต้องการเช็คหรือไม่สำหรับความพยายามในการเพิ่มคีย์เดียวกันสองครั้ง

ขออภัยสำหรับโพสต์ที่ยาวฉันหวังว่ามันจะโอเค


+1 น่าสนใจมากขอบคุณสำหรับโพสต์ของคุณ! ดูเหมือนว่าการแสดงจะเหมือนกันเกือบทั้งหมดที่นี่เนื่องจากผู้โพสต์คนอื่น ๆ ได้บอกใบ้เกี่ยวกับการค้นหาที่ยอดเยี่ยม :)
Sune Rievers

70

เวอร์ชันแรกจะเพิ่ม KeyValuePair ใหม่ลงในพจนานุกรมหากมีคีย์อยู่ในพจนานุกรมแล้ว อย่างที่สองโดยใช้ตัวสร้างดัชนีจะเพิ่มคู่ใหม่หากไม่มีคีย์ แต่จะเขียนทับค่าของคีย์หากมีอยู่แล้วในพจนานุกรม

IDictionary<string, string> strings = new Dictionary<string, string>();

strings["foo"] = "bar";          //strings["foo"] == "bar"
strings["foo"] = string.Empty;   //strings["foo"] == string.empty
strings.Add("foo", "bar");       //throws     

+1 คุณมีแหล่งข้อมูลข้างต้นหรือไม่? ฉันสนใจที่จะเรียนรู้ว่ามีผลข้างเคียงหรือข้อแม้ในการใช้แบบฟอร์มแรกหรือแบบหลังหรือไม่
Sune Rievers

3
ไม่มีแหล่งที่มาเช่นนี้จริงๆเพียงแค่อยู่เหนือศีรษะของฉัน แต่ฉันไม่คิดว่าจะมีอะไรมากกว่าที่กล่าวไว้ในความคิดเห็นอื่น ๆ ถ้าฉันจำไม่ผิด Add ก็ใช้ตัวทำดัชนี แต่ตรวจสอบก่อนว่ามีการใช้งานคีย์แล้วหรือไม่
hhravn

1
เปลี่ยนคำตอบที่ยอมรับเป็นของ Steffen เนื่องจากเอกสารของเขาเป็นสิ่งที่ดีที่สุด นี่ยังคงเป็นคำตอบที่ดีแม้ว่า
Sune Rievers

@Sune: การเคลื่อนไหวที่ไม่ดี ... โดยส่วนตัวฉันคิดว่าคำตอบนี้คือถนนข้างหน้าของ Steffen ... ตรงประเด็นและเป็นตัวอย่างที่ดี
demoncodemonkey

1
@SuneRievers ฉันคิดว่ามันจะเป็นประโยชน์มากกว่าสำหรับผู้คนหากได้รับคำตอบสำหรับสิ่งนี้แทนที่จะเป็นคำตอบที่ยอมรับในปัจจุบัน เนื่องจากสิ่งนี้ตอบคำถามได้ตรงประเด็น ("อะไรคือความแตกต่าง") แทนที่จะเป็นคำถามที่ได้รับการยอมรับ (ซึ่งพูดถึงประสิทธิภาพและเกือบ 99% ของผู้ใช้ที่ค้นหาหัวข้อนี้ (เช่นฉัน) ต้องการ "ความแตกต่าง" (ทำไมฉันถึงพบสิ่งนี้ topic) และคำตอบที่ได้รับการยอมรับก็ไร้ประโยชน์สำหรับฉันและทำให้เสียเวลาที่สองของเราแทนคำตอบนี้ถูกต้อง
ที

30

Dictionary.Add(key, value)และDictionary[key] = valueมีวัตถุประสงค์ที่แตกต่างกัน:

  • ใช้Addวิธีการเพิ่มคู่คีย์ / ค่าใหม่คีย์ที่มีอยู่จะไม่ถูกแทนที่ ( ArgumentExceptionถูกโยนทิ้ง)
  • ใช้ตัวทำดัชนีหากคุณไม่สนใจว่าคีย์นั้นมีอยู่แล้วในพจนานุกรมหรือไม่กล่าวอีกนัยหนึ่งคือเพิ่มคู่คีย์ / ค่าหากคีย์ไม่อยู่ในพจนานุกรมหรือแทนที่ค่าสำหรับคีย์ที่ระบุหากคีย์นั้นมีอยู่แล้ว ในพจนานุกรม

1
รหัสที่อธิบายเจตนาในตัวเองมีความสำคัญและมีคุณค่าอย่างยิ่ง (และต้องการความคิดเห็นเพียงเล็กน้อยที่ไม่มีเลย) คำตอบนี้แสดงให้เห็นถึงความแตกต่างในเจตนาของทั้งสองวิธีและควรปฏิบัติตามเมื่อเลือกวิธีใดวิธีหนึ่ง กล่าวอีกนัยหนึ่งคืออย่าใช้ 'ตัวสร้างดัชนีเพิ่ม' เมื่อคุณรู้ล่วงหน้าว่าคุณจะเพิ่มเสมอหรือแม้กระทั่งต้องเพิ่มเสมอ การมีข้อยกเว้น IndexOutOfBounds โยนดีกว่าพฤติกรรมที่ไม่คาดคิด
ryancdotnet

29

ในการตอบคำถามก่อนอื่นเราต้องดูจุดประสงค์ของพจนานุกรมและเทคโนโลยีพื้นฐาน

Dictionary คือรายชื่อของ KeyValuePair<Tkey, Tvalue>ที่แต่ละค่าแสดงด้วยคีย์เฉพาะของมัน สมมติว่าเรามีรายการอาหารโปรดของคุณ แต่ละค่า (ชื่ออาหาร) แสดงด้วยคีย์เฉพาะ (ตำแหน่ง = คุณชอบอาหารนี้มากแค่ไหน)

รหัสตัวอย่าง:

Dictionary<int, string> myDietFavorites = new Dictionary<int, string>()
{
    { 1, "Burger"},
    { 2, "Fries"},
    { 3, "Donuts"}
};

สมมติว่าคุณต้องการที่จะมีสุขภาพที่ดีคุณเปลี่ยนใจและต้องการแทนที่ "เบอร์เกอร์" ที่คุณชื่นชอบด้วยสลัด รายการของคุณยังคงเป็นรายการโปรดของคุณคุณจะไม่เปลี่ยนลักษณะของรายการ รายการโปรดของคุณจะยังคงเป็นอันดับหนึ่งในรายการมีเพียงมูลค่าเท่านั้นที่จะเปลี่ยนไป นี่คือเมื่อคุณเรียกสิ่งนี้ว่า:

/*your key stays 1, you only replace the value assigned to this key
  you alter existing record in your dictionary*/
myDietFavorites[1] = "Salad";

แต่อย่าลืมว่าคุณเป็นโปรแกรมเมอร์และจากนี้ไปคุณจะจบประโยคด้วย คุณปฏิเสธที่จะใช้อิโมจิเพราะจะทำให้เกิดข้อผิดพลาดในการคอมไพล์และรายการโปรดทั้งหมดเป็น 0 ดัชนี

การกินของคุณก็เปลี่ยนไปเช่นกัน! ดังนั้นคุณจึงแก้ไขรายการของคุณอีกครั้ง:

/*you don't want to replace Salad, you want to add this new fancy 0
  position to your list. It wasn't there before so you can either define it*/
myDietFavorites[0] = "Pizza";

/*or Add it*/
myDietFavorites.Add(0, "Pizza");

มีความเป็นไปได้สองประการในการกำหนดคุณอาจต้องการให้คำจำกัดความใหม่สำหรับสิ่งที่ไม่มีมาก่อนหรือคุณต้องการเปลี่ยนคำจำกัดความที่มีอยู่แล้ว

วิธีการเพิ่มช่วยให้คุณสามารถเพิ่มระเบียนได้ แต่ต้องอยู่ภายใต้เงื่อนไขเดียวเท่านั้น: คีย์สำหรับคำจำกัดความนี้อาจไม่มีอยู่ในพจนานุกรมของคุณ

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

ฉันจะใช้อัลกอริทึมการแฮช CRC32 เพื่อทำให้ตัวอย่างของฉันง่ายขึ้น เมื่อคุณกำหนด:

myDietFavorites[0] = "Pizza";

สิ่งที่จะไปในถังคือdb2dc565 "Pizza" (แบบง่าย)

เมื่อคุณแก้ไขค่าด้วย:

myDietFavorites[0] = "Spaghetti";

คุณแฮช 0 ของคุณซึ่งเป็นdb2dc565อีกครั้งจากนั้นคุณค้นหาค่านี้ในที่เก็บข้อมูลเพื่อดูว่ามีอยู่หรือไม่ หากมีคุณเพียงแค่เขียนค่าที่กำหนดให้กับคีย์ใหม่ หากไม่มีคุณจะใส่มูลค่าของคุณลงในถัง

เมื่อคุณเรียกใช้ฟังก์ชันเพิ่มในพจนานุกรมของคุณเช่น:

myDietFavorite.Add(0, "Chocolate");

คุณแฮช 0 เพื่อเปรียบเทียบค่ากับค่าในที่เก็บข้อมูล คุณอาจจะวางไว้ในถังแต่ถ้ามันไม่ได้มี

สิ่งสำคัญคือต้องรู้ว่ามันทำงานอย่างไรโดยเฉพาะอย่างยิ่งถ้าคุณทำงานกับพจนานุกรมของสตริงหรือคีย์ประเภทถ่าน เป็นกรณีที่ละเอียดอ่อนเนื่องจากอยู่ระหว่างการแฮช ตัวอย่างเช่น "name"! = "Name" ลองใช้ CRC32 เพื่ออธิบายสิ่งนี้

ค่าสำหรับ "name" คือ: e04112b1 ค่าสำหรับ "ชื่อ" คือ1107fb5b


สองบรรทัดนี้ก็เพียงพอที่จะเข้าใจ ....... มีความเป็นไปได้สองประการในการกำหนดคุณอาจต้องการให้คำจำกัดความใหม่สำหรับสิ่งที่ไม่มีมาก่อนหรือคุณต้องการเปลี่ยนนิยามที่มีอยู่แล้ว วิธีการเพิ่มช่วยให้คุณสามารถเพิ่มระเบียนได้ แต่ต้องอยู่ภายใต้เงื่อนไขเดียวเท่านั้น: คีย์สำหรับคำจำกัดความนี้อาจไม่มีอยู่ในพจนานุกรมของคุณ
Niraj Trivedi

แสดงความคิดเห็นได้ดีพอ ๆ กับ "ดูในเอกสารประกอบ"
Kamil Kurzynowski

4

ใช่นั่นคือความแตกต่างวิธีการเพิ่มจะแสดงข้อยกเว้นหากมีคีย์อยู่แล้ว

เหตุผลที่ต้องใช้วิธีการเพิ่มมีดังนี้ หากพจนานุกรมไม่ควรมีคีย์อยู่แล้วคุณมักต้องการข้อยกเว้นเพื่อให้คุณทราบถึงปัญหา


0

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

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

dict[key] = valueหมายถึงดีกว่าทดแทน ถ้าฉันเห็นรหัสนั้นฉันคาดว่าครึ่งหนึ่งจะอยู่ในพจนานุกรมอยู่แล้ว


ฉันคิดว่ามีประสิทธิภาพเพิ่มขึ้นเล็กน้อยจากการไม่ตรวจสอบว่ามีคีย์อยู่ก่อนหรือไม่ ฉันไม่คาดหวังdic[key] = valueว่าจะมีกุญแจอยู่แล้ว แต่ฉันเดาว่ามันเป็นเรื่องที่ถกเถียงกันได้;)
Sune Rievers

2
+ ฉันคิดว่าไม่ควรใช้การขว้างปาเป็นวิธีตรวจสอบว่ามีการแสดงคีย์แล้วหรือไม่ if (! strings.ContainsKey ("foo")) strings.Add ("foo", "bar");
hhravn


0

เพื่อแทรกค่าลงในพจนานุกรม

 Dictionary<string, string> dDS1 = new Dictionary<string, string>();//Declaration
 dDS1.Add("VEqpt", "aaaa");//adding key and value into the dictionary
 string Count = dDS1["VEqpt"];//assigning the value of dictionary key to Count variable
 dDS1["VEqpt"] = Count + "bbbb";//assigning the value to key
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.