รายชื่อพจนานุกรม


30

ดังนั้นฉันจึงเจองานDictionary<int, int>วันนี้ สิ่งนี้ดูแปลกสำหรับฉันเพราะฉันอาจจะใช้List<int>แทน มีความแตกต่างและจะมีกรณีการใช้งานที่โครงสร้างหนึ่งจะเป็นที่ต้องการมากกว่าอีกหรือไม่


1
จำเป็นต้องมีความสัมพันธ์ระหว่าง ints สองตัว จากนั้นแผนที่ (พจนานุกรมในภาษานี้) เหมาะสม
Rig

3
พจนานุกรมชื่อทำให้ฉันชัดเจน เมื่อคุณต้องการค้นหาบางสิ่งอย่างรวดเร็วคุณต้องใช้พจนานุกรม
ChaosPandion

2
@ChaosPandion กList<T>ภายในกรอบ NET เป็นอาร์เรย์เข้าถึงโดยสุ่มซึ่งการดำเนินการค้นหาเป็นปกติได้เร็วขึ้นDictionary<int,T>กว่าสำหรับ
Doc Brown

2
@DocBrown - เฉพาะในกรณีที่ค่อนข้างแปลกของการใช้ดัชนีตัวเลขเป็นกุญแจสำคัญ อื่น ๆ ฉลาดมองขึ้นเป็น gonna Dictionary<TKey, TValue>จะได้เร็วขึ้นเมื่อใช้
ChaosPandion

2
@chaos คำถามนี้เกี่ยวกับกรณีแปลก ๆ
MarkJ

คำตอบ:


32

คุณจะใช้ a Dictionary<int, int>หากดัชนีของคุณมีความหมายพิเศษนอกเหนือจากตำแหน่งเพียงตำแหน่ง

ตัวอย่างทันทีที่ทราบคือการจัดเก็บคอลัมน์ id และคอลัมน์ int ในฐานข้อมูล ตัวอย่างเช่นถ้าคุณมี[person-id]คอลัมน์และคอลัมน์แล้วคุณอาจจะนำผู้ที่เป็น[personal-pin] Dictionary<int, int>วิธีนี้pinDict[person-id]จะช่วยให้คุณ PIN แต่ดัชนีมีความหมายและไม่เพียง List<int>แต่อยู่ในตำแหน่งได้

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


หากรหัสบุคคลของฉันมาจากช่วง 0, ... , 999 และฉันจะต้องโหลดค่าพินส่วนบุคคลลงในหน่วยความจำสำหรับ 1,000 คนทั้งหมดฉันมักจะเลือกList<int>และไม่ใช่พจนานุกรม ดูคำตอบของฉันด้านล่าง
Doc Brown

3
ใช่ แต่พจนานุกรมอาจกระจัดกระจาย
jk

@jk: นั่นคือสิ่งที่ฉันพยายามอธิบายอย่างละเอียดในคำตอบของฉัน
Doc Brown

7
PIN ส่วนตัวหรือไม่ เสียงที่ซ้ำซ้อน
แจ็ค

หืมเมื่อดัชนีมี "ความหมายพิเศษ" ในสถานการณ์โลกแห่งความเป็นจริงอาจเป็นไปได้ว่าพวกเขาไม่ได้อยู่ในช่วงที่ต่อเนื่องกัน [0, ... , n] (แม้ว่านี่จะไม่ได้บังคับ) ดังนั้นคำตอบนี้คือ ไม่ผิดธรรมดา แต่ไม่แน่ชัด อย่างไรก็ตาม IMHO การตัดสินใจไม่ควรขึ้นอยู่กับ "สิ่งที่มีความหมายพิเศษ" แต่ใน "คีย์จะสร้างช่วงเวลาโดยประมาณ [0, ... , n]" จากจำนวน upvotes ฉันเดาว่าผู้อ่านส่วนใหญ่พลาดจุดนั้นไป
Doc Brown

28

คิดว่าListเป็นอาร์เรย์และDictionaryเป็นตารางแฮช คุณจะใช้Dictionaryถ้าคุณต้องการแมป (หรือเชื่อมโยง) คีย์ที่มีความหมายกับค่าในขณะที่Listตำแหน่ง (หรือดัชนี) หรือแมป () เชื่อมโยงเท่านั้น) กับค่า

ตัวอย่างเช่นสมมติว่าคุณต้องการจัดเก็บความสัมพันธ์ระหว่างอายุของบุคคลและความสูง คุณสามารถใช้Dictionary<int, int>เพื่อทำแผนที่อายุของบุคคล (หนึ่งint) ให้สูงที่สุด (an int):

Dictionary<int, int> personHeightMap = new Dictionary<int, int>();

personHeightMap.Add(21, 185);
personHeightMap.Add(31, 174);

int height = personHeightMap.ContainsKey(21) ? personHeightMap[21] : -1;

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


7
+1 สำหรับการกล่าวขวัญว่าListข้อเสนอที่มีการสั่งซื้อซึ่งเป็นDictionaryข้อตกลงกับสมาคม หากคุณต้องการรับข้อมูลของคุณในลำดับที่แน่นอนทุกครั้งหรือลำดับของพวกเขาที่เกี่ยวข้องกับแต่ละอื่น ๆ เป็นสิ่งสำคัญ a Listเป็นวิธีที่จะไป Dictionariesมีแนวโน้มที่จะไม่เรียงลำดับและจัดการกับคีย์การแมป -> ความสัมพันธ์ที่มีค่า
KChaloux

2
สุดท้ายไม่น้อยเมื่อคุณรู้ว่าสิ่งที่คุณกำลังมองหาตารางแฮชอยู่ที่ประมาณ O (1) เวลาในขณะที่อาร์เรย์เป็น O (logN) ในกรณีที่ดีที่สุด (เรียงและ w / o ซ้ำ) และ O (N) ใน กรณีที่เลวร้ายที่สุด
JensG

1
+1 ดูเหมือนว่าไม่มีใครพูดถึงประเด็นที่ว่ารายการต่าง ๆ มีการเรียงลำดับความหมายและการค้นหาเป็นการกำหนดความหมายซึ่งเป็นพื้นฐานอย่างยิ่งในความคิดของฉัน
Benjamin Hodgson

15

Semantically, a Dictionary<int, T>และList<T>คล้ายคลึงกันมากทั้งสองเป็น container access แบบสุ่มของ. NET Framework ในการใช้รายการแทนพจนานุกรมคุณต้องมีค่าพิเศษในประเภทของคุณT(เช่นnull) เพื่อแสดงช่องว่างในรายการของคุณ หากTไม่ใช่ประเภท nullable เช่นintคุณสามารถใช้int?แทนหรือถ้าคุณเป็นเพียงการคาดหวังว่าจะเก็บค่าบวกคุณยังสามารถใช้ค่าพิเศษเช่น -1 เพื่อเป็นตัวแทนของช่องว่าง

ตัวเลือกใดที่คุณควรเลือกจะขึ้นอยู่กับช่วงของค่าคีย์ หากกุญแจของคุณอยู่ในDictionary<int, T>อยู่ในช่วงจำนวนเต็มโดยไม่มีช่องว่างจำนวนมาก (เช่น 80 ค่าจาก [0, ... 100]) ดังนั้น a List<T>จะเหมาะสมกว่าเนื่องจากการเข้าถึงโดยดัชนีเร็วกว่าและ มีหน่วยความจำและค่าใช้จ่ายน้อยลงเมื่อเทียบกับพจนานุกรมในกรณีนี้

หากค่าคีย์ของคุณคือ 100 intค่าจากช่วงเช่น [0, ... , 1000000] ดังนั้นList<T>หน่วยความจำจำเป็นต้องเก็บค่า 1000000 ของ T ซึ่งพจนานุกรมของคุณจะต้องใช้หน่วยความจำตามลำดับขนาดประมาณ 100 ค่า T 100 ค่าของ int (บวกค่าใช้จ่ายในความเป็นจริงคาดว่าประมาณ 2 เท่าของหน่วยความจำสำหรับการจัดเก็บ 100 คีย์และค่าเหล่านั้น) ดังนั้นในกรณีหลังพจนานุกรมจะเหมาะสมกว่า


6
นี่คือความแตกต่างที่สำคัญ imho พจนานุกรม <int, int> สามารถกระจัดกระจาย
jk

ในกรณีนั้นเราไม่สามารถใช้ List <KeyValuePair <int, int >> ได้หรือไม่ อันไหนจะดีกว่าสำหรับการสำรวจเส้นทางเชิงเส้น?
Deepak Mishra

@DeepakMishra: ความแตกต่างที่สำคัญList<KeyValuePair<int,T>>คือไม่มีการดำเนินการค้นหา O (1) ประการที่สององค์ประกอบในList<KeyValuePair<int,T>>สามารถมีการสั่งซื้อที่เฉพาะเจาะจงเป็นอิสระจากค่าคีย์ของพวกเขา หากคุณต้องการหลัง แต่ไม่ใช่อดีตList<KeyValuePair<int,T>>หรือList<Tuple<int,T>>อาจเป็นทางเลือกที่ดีกว่า OrderedDictionaryหากคุณจำเป็นต้องใช้ทั้งยังมี
Doc Brown

@DocBrown อันไหนจะดีกว่าสำหรับการสำรวจเส้นทางเชิงเส้น (เช่น foreach) และการดำเนินการแทรกไม่จำเป็นต้องค้นหาโดยตรง?
Deepak Mishra

@DeepakMishra: ไม่มีสิ่งเช่น "ดีกว่าโดยทั่วไป" ในการพัฒนาซอฟต์แวร์ ดีกว่าที่นี่อาจหมายถึงเร็วกว่าอ่านดีกว่าพิมพ์รหัสน้อยลงขยายได้ง่ายขึ้นสำหรับความต้องการที่จะเกิดขึ้น แต่โดยทั่วไปให้หยุดคิดมากใช้สิ่งที่แก้ปัญหาของคุณได้อย่างถูกต้องและง่ายที่สุดในสายตาตรวจสอบว่ามันเร็วพอสำหรับจุดประสงค์ของคุณและลงทุนในความคิดที่มากขึ้นเมื่อคุณสังเกตเห็นข้อเสีย
Doc Brown

6

ใครจะคิดว่าพวกเขาเทียบเท่ากันได้?

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

จะมีสถานการณ์น้อยมากที่สถานการณ์หนึ่งไม่ได้เหนือกว่าสถานการณ์อื่นอย่างมาก


2

นอกเหนือ: ภาษาการเขียนโปรแกรมอื่น ๆ อ้างถึงโครงสร้างข้อมูลประเภทนี้เป็นแผนที่ไม่ใช่พจนานุกรม

หากข้อมูลของคุณสามารถกำหนดอย่างมีความหมายเป็นคู่ของคีย์ / ค่าพจนานุกรมจะให้การเข้าถึงที่รวดเร็วยิ่งขึ้นถ้าคุณต้องการค้นหาค่าโดยใช้คีย์

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

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


1

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

เพิ่มเติมเกี่ยวกับ .... รายการพจนานุกรมพร้อมตัวอย่าง


-1

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


-3

เหล่านี้เป็นคำตอบที่ดีที่ดูเหมือนจะครอบคลุมฐาน

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


8
ฉันไม่เห็นด้วย. พจนานุกรม / แผนที่เป็นโครงสร้างข้อมูลพื้นฐานที่วิศวกรซอฟต์แวร์ทุกคนควรคุ้นเคยอย่างใกล้ชิด ไม่ว่าจะด้วยวิธีใด: คุณจะต้องมีเหตุผลที่สมเหตุสมผลในการใช้โครงสร้างข้อมูลใด ๆ รวมถึงรายการ
Steven Evers
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.