Golang neden ayarlanmış bir veri yapımız yok [kapalı]


130

Bir sete sahip olmamı gerektiren "Go programlama dili" alıştırması # 1.4'ü çözmeye çalışıyorum. Bir set türü oluşturabilirim ama dil neden biriyle gelmiyor? go, google'dan geldiği için, guava'nın da ortaya çıktığı yer, dil tasarımcıları neden temel veri yapıları için destek eklemeyi tercih etmediler? neden kullanıcılarınızı set olarak bu kadar basit bir şey için kendi uygulamalarını oluşturmaya zorluyorsunuz?


11
hmmm. neden olumsuz oy verdiğini merak ediyor musunuz? Jenerikler olmasa bile, neredeyse en başından beri bir setimizin olduğu java dünyasından geliyorum. Bu yüzden, bu davranışı çok tuhaf buluyorum
anjanb

Yanıtlar:


83

Kısmen, Go jeneriklere sahip olmadığı için (bu nedenle her tür için bir set-türüne ihtiyacınız olacak veya yansımaya geri döneceksiniz, bu oldukça verimsizdir).

Kısmen, çünkü ihtiyacınız olan tek şey "bir kümeye tek tek öğeler eklemek / kaldırmak" ve "göreceli olarak alan verimli" ise, bunun bir kısmını basitçe a kullanarak elde edebilirsiniz map[yourtype]bool(ve kümedeki trueherhangi bir öğe için değeri olarak ayarlayın) ) veya daha fazla alan verimliliği için değer olarak boş bir yapı kullanabilir _, present = the_setoid[key]ve mevcudiyeti kontrol etmek için kullanabilirsiniz .


1
Ayrıca, seti başka bir kodda "satır içine alarak" ya da gerektiğinde kendi set türünüzü tanımlayarak kendi kodunuzda yazmak Go'nun ruhuna uygun görünüyor. Her neyse, örneğin C ++ 'da std :: set <T> kullanmak, her zaman bir işlev uygulamasının parçası olarak veya başka bir veri yapısını gerçekleştirirken gerçekleşir. Bu nedenle, diğer veri yapısını doğrudan haritaları, dilimleri ve ihtiyacınız olan diğer yapı taşlarını kullanarak ancak herhangi bir yerleşik set olmadan uygulayın. Bir setin her kullanımı onu zaten biraz farklı şekilde kullanacak :)
Bjarke Ebert

1
Ancak genellikle kendi başına bir <Foo> kümesine gerçekten ihtiyacınız yoktur, daha büyük bir şeyi uygulamanın bir parçası olarak bir <Foo> kümesi kullanırsınız. "Yeniden kullanılabilir" bir bileşeni eklemek için yapmanız gereken şeylerin, ihtiyaçtan kaçınmaktan çok daha kötü olduğu tonlarca kod gördüm. İşte burada bir <Foo> setimiz var, oradaki fonksiyonun bir set <Bar> ihtiyacı var, oops, kovaryansımız var mı, yoksa bu şeyin böyle görünmesi için bir WrapperFactory yapmaya ne dersiniz, vb. Belki o diğer fonksiyon gerçekten sadece üyeliği kontrol edebilen bir arayüze ihtiyaç duyar, bu yüzden ona bir set <Foo> göndermeyin.
Bjarke Ebert

42
Öyleyse, jenerik yoksa, 'genel' harita nasıl uygulanmaktadır?
Fermin Silva

26
Bayt kaydetmek istiyorsanız, map[T]struct{}yerine kullanabileceğinizi unutmayın map[T]bool.
2017


69

Bunun bir nedeni, haritadan bir set oluşturmanın kolay olmasıdır:

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

Birlik

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

kesişim

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

Diğer tüm set işlemlerini uygulamak gerçekten o kadar da zor değil.


10
Varlığı kontrol etmek, haritayı indekslemektir. Çünkü içinde değilse, sıfır değeri (olan false) bunu doğru bir şekilde söyleyecektir. Test için virgül-ok deyimine gerek yok.
icza

2
Kavşak uygulaması, farklılık için böyle görünüyor.
musiphil

1
@Kittsil teşekkür ederim. Güncellenmiş.
Salvador Dali

34
Bunun map[int]struct{}yerine kullanılması daha uygundur bool, çünkü boş bir yapı bellekte 0 bayt kaplar. Kısa süre önce bu ana
BG Adrian

13
Bu o kadar kolay değil. Sadece bir Set kullanmanız gereken her yere bu kodu yazmak zorunda kalmak, bugünlerde bana gülünç geliyor. Koleksiyon desteği herhangi bir dil tarafından sağlanmalıdır. Daha iyi bir cevabın, Go'nun henüz olgunlaşmaması olduğunu düşünün. Eminim yakında bunu kapsayacak kütüphaneler olacaktır.
Stef

5

Vatine'nin yazdığı gibi: go jeneriklerden yoksun olduğundan, standart kitaplığın değil, dilin bir parçası olması gerekir. Bunun için dili anahtar kelime kümesi, birleşim, kesişim, fark, alt küme ile kirletmeniz gerekir ...

Diğer bir neden ise, bir kümenin "doğru" uygulamasının ne olduğunun hiç net olmamasıdır:

  1. İşlevsel bir yaklaşım var:

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

Bu, tüm eşitliklerin bir kümesidir. Çok verimli bir arama ve birleşim, kesişme, fark ve alt küme, fonksiyonel kompozisyon ile kolaylıkla yapılabilir.

  1. Ya da Dali'nin gösterdiği gibi, benzer bir yaklaşım yaparsınız.

Değerle ilişkili bir şeyi sakladığınız için haritada böyle bir sorun yoktur.


2
Buit-in kümelerini işlemek için, Pascal bir grup ikili (iki argmnent) operatörü aşırı yükler: +birlik -için, fark *için, kesişim <=için, alt küme >=için, süper küme için, =eşitlik <>için, eşitsizlik için ve inüyelik için. Yani Go'da, yalnızca tek bir yeni anahtar kelime - in. Öte yandan, Pascal'ın yerleşik kümeleri yalnızca "sıra sayıları" üzerinde çalışır - yani, belirli büyüklükte bir tamsayı değerinin altında yatan temsili olan herhangi bir tür.
kostix

9
Bir seti uygulamanın birden fazla yolu olduğu gerçeği, diğer birçok dilin bunları sağlamasını engellememiştir.
augurar

@kostix: Git bile sözdizimi kullanabilirsiniz s[key](sanki sbir vardı map[T]boolyerine) key in s.
musiphil

2
Sadece geri dönmemek için bir neden var n % 2 == 0mı?
João Andrade

4

Diğer bir olasılık, en az bir paketin olduğu veya yerleşik büyük paketi kullanabileceğiniz bit kümelerini kullanmaktır . Bu durumda, temel olarak nesnenizi bir dizine dönüştürmek için bir yol tanımlamanız gerekir.


1
Yukarıda atıfta bulunulan bit seti paketinin orijinal versiyonunu yazdığımı not etmeliyim.
Will Fitzgerald
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.