golang ทำไมเราไม่มีการกำหนดโครงสร้างข้อมูล [ปิด]


131

ฉันกำลังพยายามแก้แบบฝึกหัด "The go programming lanaguage" # 1.4 ซึ่งทำให้ฉันต้องมีชุด ฉันสามารถสร้างประเภทชุดได้ แต่ทำไมไม่มีภาษามาด้วย ไปเพราะมาจาก google ซึ่งฝรั่งก็กำเนิดขึ้นด้วยเหตุใดนักออกแบบภาษาจึงไม่เลือกที่จะเพิ่มการรองรับโครงสร้างข้อมูลพื้นฐาน เหตุใดจึงบังคับให้ผู้ใช้ของคุณสร้างการใช้งานของตนเองสำหรับบางสิ่งที่เรียบง่ายเป็นชุด


11
อืมม สงสัยว่าทำไมโหวตลบ? ฉันมาจากโลก java ที่เรามีชุดเกือบจะถูกต้องตั้งแต่เริ่มต้นแม้จะไม่มีชื่อสามัญ ดังนั้นฉันจึงพบว่าพฤติกรรมนี้เป็นเรื่องแปลกประหลาด
anjanb

คำตอบ:


84

ส่วนหนึ่งเป็นเพราะ Go ไม่มี generics (ดังนั้นคุณจะต้องมี set-type หนึ่งชุดสำหรับทุกประเภทหรือถอยกลับไปที่การสะท้อนซึ่งค่อนข้างไม่มีประสิทธิภาพ)

ส่วนหนึ่งเป็นเพราะหากคุณต้องการเพียง "เพิ่ม / ลบองค์ประกอบแต่ละรายการลงในชุด" และ "ค่อนข้างประหยัดพื้นที่" คุณจะได้รับสิ่งที่ยุติธรรมเพียงแค่ใช้ a map[yourtype]bool(และตั้งค่าเป็นtrueสำหรับองค์ประกอบใด ๆ ในชุด ) หรือเพื่อเพิ่มประสิทธิภาพของพื้นที่คุณสามารถใช้โครงสร้างว่างเป็นค่าและใช้_, present = the_setoid[key]เพื่อตรวจสอบการมีอยู่


1
นอกจากนี้ดูเหมือนว่า Go จะเขียนออกมาในโค้ดของคุณเองไม่ว่าจะโดย "inlining" ชุดในโค้ดอื่นหรือกำหนดประเภทชุดของคุณเองเมื่อจำเป็น อย่างไรก็ตามการใช้ตัวอย่างเช่น std :: set <T> ใน C ++ มักเกิดขึ้นเป็นส่วนหนึ่งของการใช้งานฟังก์ชันหรือการใช้โครงสร้างข้อมูลอื่น ๆ ดังนั้นเพียงใช้โครงสร้างข้อมูลอื่นนั้นโดยตรงโดยใช้แผนที่และชิ้นส่วนและสิ่งที่จำเป็นอื่น ๆ ที่คุณต้องการ แต่ไม่ต้องตั้งค่าใด ๆ ในตัว การใช้งานแต่ละชุดจะใช้แตกต่างกันเล็กน้อยอยู่ดี :)
Bjarke Ebert

1
แต่โดยปกติคุณไม่จำเป็นต้องใช้ชุด <Foo> ด้วยตัวมันเองคุณใช้ชุด <Foo> เป็นส่วนหนึ่งของการนำสิ่งที่ใหญ่กว่าไปใช้ ฉันเคยเห็นโค้ดมากมายที่สิ่งที่คุณต้องทำเพื่อรวมส่วนประกอบที่ "ใช้ซ้ำได้" นั้นแย่กว่าการหลีกเลี่ยงความจำเป็น ที่นี่เรามีชุด <Foo> ฟังก์ชันตรงนั้นต้องการชุด <Bar> อ๊ะเรามีความแปรปรวนร่วมหรือยังหรือจะสร้าง WrapperFactory เพื่อให้สิ่งนี้เป็นแบบนี้เป็นต้นบางทีฟังก์ชันอื่น ๆ ต้องการแค่อินเทอร์เฟซที่สามารถตรวจสอบการเป็นสมาชิกได้ดังนั้นอย่าส่งชุด <Foo>
Bjarke Ebert

43
ดังนั้นหากไม่มีข้อมูลทั่วไปแผนที่ 'ทั่วไป' จะใช้งานได้อย่างไร?
Fermin Silva

26
โปรดทราบว่าหากคุณต้องการบันทึกไบต์คุณสามารถใช้map[T]struct{}แทนmap[T]boolไฟล์.
emersion

4
ดูได้ที่emersion.fr/blog/2017/sets-in-go
emersion

69

เหตุผลหนึ่งคือการสร้างชุดจากแผนที่นั้นง่ายมาก:

s := map[int]bool{5: true, 2: true}
_, ok := s[6] // check for existence
s[8] = true // add element 
delete(s, 2) // remove element

สหภาพ

s_union := map[int]bool{}
for k, _ := range s1{
    s_union[k] = true
}
for k, _ := range s2{
    s_union[k] = true
}

การตัด

s_intersection := map[int]bool{}
for k,_ := range s1 { 
  if s2[k] {
    s_intersection[k] = true
  }
}

ไม่ใช่เรื่องยากที่จะใช้การดำเนินการชุดอื่น ๆ ทั้งหมด


10
ตรวจสอบการมีอยู่เป็นเพียงการจัดทำดัชนีแผนที่ เนื่องจากถ้าไม่มีอยู่ค่าศูนย์ (ซึ่งเป็นfalse) จะบอกได้อย่างถูกต้อง ไม่จำเป็นต้องมีสำนวนคอมมาโอเคสำหรับการทดสอบ
icza

2
การใช้งานสำหรับจุดตัดดูเหมือนว่าจะแตกต่างกัน
musiphil

1
@Kittsil ขอบคุณครับ. Updated
Salvador Dali

34
เป็นวิธีที่ดีที่สุดที่จะใช้map[int]struct{}แทนboolเนื่องจากโครงสร้างที่ว่างเปล่ามีพื้นที่ 0 ไบต์ในหน่วยความจำ ฉันเพิ่งเขียนส่วนสำคัญสำหรับgist.github.com/bgadrian/cb8b9344d9c66571ef331a14eb7a2e80
BG Adrian

14
นั่นไม่ใช่เรื่องง่ายเลย แค่ต้องเขียนโค้ดนั้นทุกที่ที่คุณต้องใช้ Set ดูเหมือนจะไร้สาระสำหรับฉันในทุกวันนี้ การสนับสนุนคอลเลกชันควรจัดให้เป็นภาษาใดก็ได้ คิดว่าคำตอบที่ดีกว่าคือ Go ยังไม่เป็นผู้ใหญ่ ฉันแน่ใจว่าจะมีห้องสมุดที่จะครอบคลุมในไม่ช้า
Stef

5

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

อีกสาเหตุหนึ่งคือยังไม่ชัดเจนว่าการใช้งานชุด "ถูกต้อง" คืออะไร:

  1. มีแนวทางการทำงาน:

    func IsInEvenNumbers(n int) bool {
        if n % 2 == 0 {
            return true
        }
       return false
    }

นี่คือชุดของ ints ทั้งหมด มันมีการค้นหาที่มีประสิทธิภาพมากและการรวมกันการตัดกันความแตกต่างและส่วนย่อยสามารถทำได้อย่างง่ายดายโดยองค์ประกอบการทำงาน

  1. หรือคุณใช้วิธีการที่เหมือนอย่างที่ Dali แสดง

แผนที่ไม่มีปัญหานั้นเนื่องจากคุณจัดเก็บบางสิ่งที่เกี่ยวข้องกับค่า


2
เพื่อจัดการกับ buit ในชุดเกิน Pascal พวงของไบนารี (สอง argmnent) ผู้ประกอบการ: +เพื่อความเป็นเอกภาพ, -ความแตกต่าง, *สำหรับแยก<=เซต, >=สำหรับซูเปอร์, =เพื่อความเท่าเทียมกัน, <>สำหรับความไม่เท่าเทียมกันและinสำหรับการเป็นสมาชิก ดังนั้นในการไปก็จะเป็นเพียงคำหลักใหม่เดียว in- ในทางกลับกันชุดในตัวของ Pascal ใช้งานได้กับ "ลำดับ" เท่านั้นนั่นคือประเภทใดก็ได้ที่มีการแสดงค่าพื้นฐานของค่าจำนวนเต็มในบางขนาด
kostix

9
ความจริงที่ว่ามีหลายวิธีในการใช้งานชุดไม่ได้หยุดภาษาอื่น ๆ จากการให้บริการ
augurar

@kostix: Go สามารถใช้ไวยากรณ์s[key](ราวกับว่าsเป็น a map[T]bool) แทนkey in s.
musiphil

2
มีเหตุผลอะไรที่ไม่กลับมาn % 2 == 0?
João Andrade

4

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


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