golang kenapa tidak kita punya set datastructure [tertutup]

130

Saya mencoba menyelesaikan latihan "Go programming lanaguage" # 1.4 yang mengharuskan saya memiliki satu set. Saya dapat membuat tipe set tetapi mengapa bahasanya tidak disertakan? pergi, berasal dari google, di mana jambu biji juga berasal, mengapa desainer bahasa tidak memilih untuk menambahkan dukungan untuk struktur data fundamental? mengapa memaksa pengguna Anda untuk membuat implementasi mereka sendiri untuk sesuatu yang begitu mendasar sebagai satu set?

anjanb.dll
sumber
11
hmmm. bertanya-tanya mengapa suara negatif? Saya berasal dari dunia java di mana kami memiliki satu set hampir sejak awal, bahkan tanpa obat generik. Jadi, menurut saya perilaku ini agak aneh
anjanb

Jawaban:

83

Sebagian, karena Go tidak memiliki generik (jadi Anda memerlukan satu set-type untuk setiap tipe, atau kembali ke refleksi, yang agak tidak efisien).

Sebagian, karena jika yang Anda butuhkan hanyalah "menambah / menghapus elemen individu ke satu set" dan "relatif hemat ruang", Anda bisa mendapatkan sedikit dari itu hanya dengan menggunakan map[yourtype]bool(dan setel nilai ke trueuntuk setiap elemen dalam set ) atau, untuk efisiensi ruang yang lebih banyak, Anda dapat menggunakan struct kosong sebagai nilai dan digunakan _, present = the_setoid[key]untuk memeriksa keberadaan.

Vatine
sumber
1
Selain itu, tampaknya menjadi semangat Go untuk hanya menuliskannya dalam kode Anda sendiri, baik dengan "menyebariskan" set dalam kode lain, atau menentukan jenis set Anda sendiri bila diperlukan. Bagaimanapun, menggunakan misalnya std :: set <T> di C ++ selalu terjadi sebagai bagian dari implementasi fungsi atau mengimplementasikan beberapa struktur data lainnya. Oleh karena itu, cukup terapkan struktur data lain tersebut secara langsung menggunakan peta dan irisan dan blok penyusun apa pun yang Anda butuhkan, tetapi tanpa kumpulan bawaan apa pun. Tiap penggunaan satu set akan menggunakannya sedikit berbeda pula :)
Bjarke Ebert
1
Tetapi biasanya Anda tidak benar-benar membutuhkan satu set <Foo> dengan sendirinya, Anda menggunakan satu set <Foo> sebagai bagian dari mengimplementasikan sesuatu yang lebih besar. Saya telah melihat banyak sekali kode di mana hal-hal yang perlu Anda lakukan untuk menyertakan komponen "dapat digunakan kembali" jauh lebih buruk daripada sekadar menghindari kebutuhan. Jadi di sini kita memiliki satu set <Foo>, fungsi itu di sana membutuhkan satu set <Bar>, oops, apakah kita belum memiliki kovarian, atau bagaimana membuat WrapperFactory untuk membuat benda ini terlihat seperti ini, dll. Mungkin fungsi lain itu benar-benar hanya membutuhkan antarmuka yang dapat memeriksa keanggotaan, jadi jangan kirimkan satu set <Foo>.
Bjarke Ebert
42
Jadi jika tidak memiliki generik, bagaimana peta 'generik' diterapkan?
Fermin Silva
26
Catatan bahwa jika Anda ingin menyimpan byte, Anda dapat menggunakan map[T]struct{}bukan map[T]bool.
emersi
69

Salah satu alasannya adalah mudah untuk membuat satu set dari peta:

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

Persatuan

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

Persimpangan

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

Tidak terlalu sulit untuk mengimplementasikan semua operasi set lainnya.

Salvador Dali
sumber
10
Memeriksa keberadaan hanya dengan mengindeks peta. Karena jika tidak ada di dalamnya, nilai nol (yang ada false) akan mengatakannya dengan benar. Tidak perlu idiom koma-ok untuk pengujian.
icza
2
Implementasi untuk persimpangan terlihat seperti itu untuk perbedaan.
musiphil
1
@Tokopedia terima kasih. Diperbarui.
Salvador Dali
34
Ini lebih optimal untuk digunakan map[int]struct{}daripada bool, karena struct kosong menempati 0 byte dalam memori. Saya baru-baru ini menulis inti untuk gist.github.com/bgadrian/cb8b9344d9c66571ef331a14eb7a2e80
BG Adrian
13
Itu tidak semudah itu. Hanya harus menulis kode itu di mana pun Anda perlu menggunakan Set tampaknya konyol bagi saya hari ini. Dukungan koleksi harus disediakan dalam bahasa apa pun. Pikirkan jawaban yang lebih baik adalah bahwa Go belum matang. Saya yakin akan ada perpustakaan yang akan membahasnya segera.
Stef
5

Seperti yang ditulis Vatine: Karena go tidak memiliki obat generik, ia harus menjadi bagian dari bahasa dan bukan pustaka standar. Untuk itu Anda kemudian harus mencemari bahasa dengan set kata kunci, union, intersection, difference, subset ...

Alasan lainnya adalah, tidak jelas sama sekali apa implementasi yang "benar" dari suatu himpunan:

  1. Ada pendekatan fungsional:

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

Ini adalah satu set dari semua int genap. Ini memiliki pencarian dan penyatuan yang sangat efisien, perpotongan, perbedaan dan subset dapat dengan mudah dilakukan dengan komposisi fungsional.

  1. Atau Anda melakukan pendekatan seperti yang ditunjukkan Dali.

Peta tidak memiliki masalah itu, karena Anda menyimpan sesuatu yang terkait dengan nilai tersebut.

0x434D53
sumber
2
Untuk menangani set buit-in, Pascal membebani sekelompok operator biner (dua-argmnent): +untuk gabungan, -untuk perbedaan, *untuk persimpangan, <=untuk subset, >=untuk superset, =untuk kesetaraan, <>untuk ketidaksetaraan dan inuntuk keanggotaan. Jadi di Go, ini hanya akan menjadi satu kata kunci baru - in. Di sisi lain, set bawaan Pascal hanya bekerja pada "ordinals" - yaitu, tipe apa pun yang memiliki representasi mendasar dari nilai integer dengan ukuran tertentu.
kostix
9
Fakta bahwa ada banyak cara untuk mengimplementasikan satu set tidak menghentikan banyak bahasa lain untuk menyediakannya.
augurar
@kostix: Go bahkan dapat menggunakan sintaks s[key](seolah-olah sa map[T]bool), bukan key in s.
musiphil
2
Ada alasan untuk tidak kembali n % 2 == 0?
João Andrade
4

Kemungkinan lain adalah menggunakan kumpulan bit, yang mana setidaknya ada satu paket atau Anda dapat menggunakan paket besar bawaan. Dalam hal ini, pada dasarnya Anda perlu menentukan cara untuk mengubah objek Anda menjadi indeks.

Will Fitzgerald
sumber
1
Saya harus mencatat bahwa saya menulis versi asli dari paket bitset yang dirujuk di atas.
Akankah Fitzgerald