996 Stimmen

Wie man Strings in Go effizient verketten kann

Im Go ist ein string ein primitiver Typ, was bedeutet, dass er schreibgeschützt ist und jede Manipulation einen neuen String erstellt.

Also, wenn ich Strings viele Male hintereinander verketten möchte, ohne die Länge des resultierenden Strings zu kennen, wie mache ich das am besten?

Der naive Ansatz wäre:

var s string
for i := 0; i < 1000; i++ {
    s += getShortStringFromSomewhere()
}
return s

aber das scheint nicht sehr effizient zu sein.

12 Stimmen

Noch eine Bank

1 Stimmen

Hinweis: Diese Frage und die meisten Antworten scheinen vor dem Hinzufügen von append() in die Sprache geschrieben worden zu sein, was eine gute Lösung dafür ist. Es wird genauso schnell wie copy() ausgeführt, aber das Slice wird zuerst erweitert, auch wenn dies bedeutet, dass ein neues zugrundeliegendes Array allokiert wird, wenn die Kapazität nicht ausreicht. bytes.Buffer macht immer noch Sinn, wenn Sie seine zusätzlichen Komfortmethoden möchten oder wenn das Paket, das Sie verwenden, dies erwartet.

10 Stimmen

Es ist nicht nur "sehr ineffizient"; es hat ein spezifisches Problem, mit dem jeder neue Nicht-CS-Mitarbeiter, den wir jemals eingestellt haben, in den ersten Wochen der Arbeit konfrontiert wird. Es ist quadratisch - O(n*n). Denken Sie an die Zahlenfolge: 1 + 2 + 3 + 4 + .... Es ist n*(n+1)/2, die Fläche eines Dreiecks mit der Basis n. Sie reservieren die Größe 1, dann die Größe 2, dann die Größe 3 usw., wenn Sie unveränderliche Strings in einer Schleife anhängen. Diese quadratische Ressourcenverwendung äußert sich auf mehrere Weisen als nur diese.

0voto

Sumer Punkte 2192

Einfache und leicht verdauliche Lösung. Details in den Kommentaren. Kopie überschreibt die Elemente des Slices. Wir schneiden ein einzelnes Element und überschreiben es.

package main

import (
    "fmt"
)

var N int = 100000

func main() {
    slice1 := make([]rune, N, N)
    //Effizient mit schneller Leistung, benötigt vorkonfigurierten Speicher
    //Wir können überprüfen, ob wir die Grenze erreicht haben, dann die Kapazität erhöhen
    //mit append, aber Strafe für das Kopieren von Daten in ein neues Array. Auch append erfolgt nach der Länge des aktuellen Slices.
    for i := 0; i < N; i++ {
        copy(slice1[i:i+1], []rune{'N'})
    }
    fmt.Println(slice1)

    //Einfache, aber schnelle Lösung. Jedes Mal, wenn die Kapazität des Slices erreicht ist, erhalten wir eine Strafe für den Aufwand, der beim Kopieren der Daten in ein neues Array entsteht
    slice2 := []rune{}
    for i := 0; i <= N; i++ {
        slice2 = append(slice2, 'N')
    }
    fmt.Println(slice2)

}

-1voto

hechen0 Punkte 306

Benchmark-Ergebnis mit Speicherzuweisungsstatistiken. Überprüfen Sie den Benchmark-Code auf GitHub.

Verwenden Sie strings.Builder zur Leistungssteigerung.

go test -bench . -benchmem
goos: darwin
goarch: amd64
pkg: github.com/hechen0/goexp/exps
BenchmarkConcat-8                1000000             60213 ns/op          503992 B/op          1 allocs/op
BenchmarkBuffer-8               100000000               11.3 ns/op             2 B/op          0 allocs/op
BenchmarkCopy-8                 300000000                4.76 ns/op            0 B/op          0 allocs/op
BenchmarkStringBuilder-8        1000000000               4.14 ns/op            6 B/op          0 allocs/op
PASS
ok      github.com/hechen0/goexp/exps   70.071s

0 Stimmen

Bitte geben Sie @cd1 für die ursprünglichen Testfälle, auf denen Sie hier aufbauen, den verdienten Kredit.

0 Stimmen

Die Frage lautet: "Wie kann man Zeichenfolgen effizient in Go verketten" nicht "Was sind die effizientesten Methoden, um Zeichenfolgen in Go zu verketten"

-4voto

liam Punkte 341

strings.Join() aus dem Paket "strings"

Wenn Sie einen Typenfehler haben (zum Beispiel wenn Sie versuchen, einen int und einen String zu verbinden), tun Sie RANDOMTYPE (die Sache, die Sie ändern möchten)

BEISPIEL:

package main

import (
    "fmt"
    "strings"
)

var intEX = 0
var stringEX = "hallo alle ihr "
var stringEX2 = "Leute hier drin"

func main() {
    s := []string{stringEX, stringEX2}
    fmt.Println(strings.Join(s, ""))
}

Ausgabe:

hallo alle ihr Leute hier drin

4 Stimmen

Dieser Code kompiliert nicht einmal: strings.Join() akzeptiert nur 2 Parameter: ein Slice und einen Trenner string.

0 Stimmen

Dies kann nicht helfen.

0 Stimmen

Fügen Sie hier einige Änderungen hinzu.

-5voto

user2288856 Punkte 43
s := fmt.Sprintf("%s%s", []byte(s1), []byte(s2))

6 Stimmen

Dies ist Lösung sehr langsam, weil es Reflexion verwendet, es analysiert den Formatstring und es erstellt eine Kopie der Daten für die []Byte(s1)-Konvertierung. Vergleichen Sie es mit anderen Lösungen, die gepostet wurden, können Sie einen einzigen Vorteil Ihrer Lösung nennen?

0 Stimmen

Dies wird nicht für eine große Anzahl von Zeichenfolgen verwendet

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X