Dilimdeki öğeyi sil


139
func main() {
    a := []string{"Hello1", "Hello2", "Hello3"}
    fmt.Println(a)
    // [Hello1 Hello2 Hello3]
    a = append(a[:0], a[1:]...)
    fmt.Println(a)
    // [Hello2 Hello3]
}

Bu ekleme fonksiyonu ile silme hilesi nasıl çalışır?

İlk öğeden önce her şeyi alıyor gibi görünüyor (boş dizi)

Sonra ilk öğeden sonra her şeyi ekleyin (sıfır konumu)

... (nokta nokta nokta) ne yapar?



3
Neden dil özelliklerine bakmıyorsunuz? ...orada ayrıntılı olarak açıklanıyor mu?
Volker

9
Bir yandan, kesinlikle doğrudur ( golang.org/ref/spec , herkes); Öte yandan, Pythonista'ları taşımak için bu deyimler hakkında yeterince tanıdık gelmedi, orada başkalarının bulması için bir açıklama yapmayı umursamıyorum.
twotwotwo

Yanıtlar:


276

aDilim nerede ve isilmek istediğiniz öğenin dizinidir:

a = append(a[:i], a[i+1:]...)

... , Go'daki değişken değişkenlerin sözdizimidir.

Temel olarak, bir işlevi tanımlarken o türden bir dilime ilettiğiniz tüm argümanları koyar. Bunu yaparak istediğiniz kadar argüman iletebilirsiniz (örneğin, istediğiniz fmt.Printlnkadar argüman alabilir).

Şimdi, bir işlevi çağırırken... , bunun tersini yapar: bir dilimi açar ve bunları değişken bir işleve ayrı argümanlar olarak iletir.

Peki bu çizgi ne yapar:

a = append(a[:0], a[1:]...)

esasen:

a = append(a[:0], a[1], a[2])

Şimdi merak ediyor olabilirsiniz, neden sadece

a = append(a[1:]...)

Eh, fonksiyon tanımlama appendolduğu

func append(slice []Type, elems ...Type) []Type

Bu yüzden ilk argüman doğru tipte bir dilim olmalı, ikinci argüman varyatiktir, bu yüzden boş bir dilim geçiriyoruz ve daha sonra argümanları doldurmak için dilimin geri kalanını açıyoruz.


35
Dilimdeki son eleman ben aralık dışında istisna almıyor musunuz? a = append(a[:i], a[i+1:]...)
themihai

5
@DaveC Projemdeki dilimleriyle çalışırken bu hatayı alıyorum: /
Tyguy7

3
@ Tyguy7 spec'ten: "Diziler veya dizeler için, 0 <= düşük <= yüksek <= len (a) ise endeksler aralıktadır, aksi takdirde aralık dışındadırlar." Belki senin durumunda yüksek <düşük; bu durumda hatayı alırsınız. ( golang.org/ref/spec#Slice_expressions )
mlg

2
Bunun performansı nasıl? Umarım kaputun altında tamamen yeni bir dilim oluşturmaz.
joonas.fi

7
@ Tyguy7 Sanırım bir döngü içindeki dilim öğelerini silmeye çalıştınız. Bu yüzden dizinlere dikkat etmelisiniz.
Nikolay Bystritskiy

42

İki seçenek vardır:

C: Dizi sırasını korumayı önemsiyorsunuz:

a = append(a[:i], a[i+1:]...)
// or
a = a[:i+copy(a[i:], a[i+1:])]

B: Siparişi tutmayı umursamazsınız (bu muhtemelen daha hızlıdır):

a[i] = a[len(a)-1] // Replace it with the last one. CAREFUL only works if you have enough elements.
a = a[:len(a)-1]   // Chop off the last one.

Diziniz işaretçilerden oluşuyorsa, bellek sızıntısıyla ilgili sonuçları görmek için bağlantıya bakın.

https://github.com/golang/go/wiki/SliceTricks


Bu ilginç, ama gerçekten soruyu cevaplamıyor
Bryan

Bu güzel, ama dizideki tek elemanı silebilirse daha iyi olurdu
Naguib Ihab

2
Sadece bir baş yukarı, ilkini b'den kullanmaya çalışın (son elemanla değiştirin), dilimdeki son elemanı çıkarmaya çalışıyorsanız açık bir şekilde çalışmaz
Sirens

13

Aksine indisler ve düşünme den [a:], - [:b]- ve [a:b]eleman endeksleri olarak -notations endeksli boşluk başlayarak yaklaşık boşluklar indeksi olarak ve elemanlar arasında bunların düşünmek 0olarak endeksli elemandan önce 0.

resim açıklamasını buraya girin

Sadece mavi sayılara baktığımızda, neler olup bittiğini görmek çok daha kolaydır: [0:3]her şeyi içine alır [3:3], boştur ve [1:2]verim verir {"B"}. Sonra [a:]sadece kısa versiyonu [a:len(arrayOrSlice)], [:b]kısa versiyon [0:b]ve [:]kısa versiyonu [0:len(arrayOrSlice)]. İkincisi, gerektiğinde bir diziyi dilime dönüştürmek için yaygın olarak kullanılır.


1
Bu cevap "hayır" themihai en etmektir açıklamaya yardımcı olmaktadır comment dave üzerine cevap atıfta bulunarak, [i + 1:] i'inci elemana atıfta bile: play.golang.org/p/E0lQ3jPcjX5
Nick P

5

... değişken değişkenlerin sözdizimidir.

Bence complier tarafından dilim kullanarak uygulanmaktadır ( []Type), sadece fonksiyon eklemek gibi:

func append(slice []Type, elems ...Type) []Type

"append" de "elems" kullandığınızda, aslında bir dilim ([]). Yani " a = append(a[:0], a[1:]...)" anlamına gelir " a = append(a[0:0], a[1:])"

a[0:0] hiçbir şeyi olmayan bir dilim

a[1:] "Hello2 Hello3"

Bu nasıl çalışır


2
a[0:0]değil nil, 0 uzunluğunda bir dilim. a[0:0]olacak tek olmak nildurumunda aolduğunu nil.
icza

5

Kabul edilen cevap çözümüyle aralık dışında bir hata alıyorum. Sebep: Aralık başladığında, tek tek yinelenen bir değer değildir, dizin tarafından yinelenir. Bir dilim kapsama alanındayken değiştirdiyseniz, bazı sorunlara neden olur.

Eski Cevap:

chars := []string{"a", "a", "b"}

for i, v := range chars {
    fmt.Printf("%+v, %d, %s\n", chars, i, v)
    if v == "a" {
        chars = append(chars[:i], chars[i+1:]...)
    }
}
fmt.Printf("%+v", chars)

Beklenen :

[a a b], 0, a
[a b], 0, a
[b], 0, b
Result: [b]

Gerçek:

// Autual
[a a b], 0, a
[a b], 1, b
[a b], 2, b
Result: [a b]

Doğru Yol (Çözüm):

chars := []string{"a", "a", "b"}

for i := 0; i < len(chars); i++ {
    if chars[i] == "a" {
        chars = append(chars[:i], chars[i+1:]...)
        i-- // form the remove item index to start iterate next item
    }
}

fmt.Printf("%+v", chars)

Kaynak: https://dinolai.com/notes/golang/golang-delete-slice-item-in-range-problem.html


3

Golang'ın wiki'sinde, bir öğeyi dilimden silmek de dahil olmak üzere dilim için bazı püf noktaları gösterir.

Bağlantı: bağlantı açıklamasını buraya girin

Örneğin a, i sayısı öğesini silmek istediğiniz dilimdir.

a = append(a[:i], a[i+1:]...)

VEYA

a = a[:i+copy(a[i:], a[i+1:])]
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.