it-swarm.com.de

Die idiomatischste Art, Elemente aus einem Array in Golang auszuwählen?

Ich habe ein Array von Strings, und ich möchte ausschließen, dass Werte, die mit foo_ OR beginnen, länger als 7 Zeichen sind.

Ich kann jedes Element durchlaufen, die if-Anweisung ausführen und es einem Abschnitt auf dem Weg hinzufügen. Aber ich war neugierig, ob es einen idiomatischen oder golangähnlichen Weg gab, dies zu erreichen.

Zum Beispiel könnte in Ruby dasselbe gemacht werden wie

my_array.select! { |val| val !~ /^foo_/ && val.length <= 7 }
20
user2490003

Es gibt keinen One-Liner wie in Ruby, aber mit einer Helper-Funktion können Sie es fast so kurz machen.

Hier ist unsere Hilfsfunktion, die eine Schleife durchläuft und nur die Elemente auswählt und zurückgibt, die einem von einem Funktionswert erfassten Kriterium entsprechen:

func choose(ss []string, test func(string) bool) (ret []string) {
    for _, s := range ss {
        if test(s) {
            ret = append(ret, s)
        }
    }
    return
}

Mit dieser Hilfsfunktion erledigen Sie Ihre Aufgabe:

ss := []string{"foo_1", "asdf", "loooooooong", "nfoo_1", "foo_2"}

mytest := func(s string) bool { return !strings.HasPrefix(s, "foo_") && len(s) <= 7 }
s2 := choose(ss, mytest)

fmt.Println(s2)

Ausgabe (probiere es auf dem Go Playground ):

[asdf nfoo_1]

Hinweis:

Wenn zu erwarten ist, dass viele Elemente ausgewählt werden, kann es sinnvoll sein, zuvor eine "große" ret-Scheibe zuzuweisen und statt der append() eine einfache Zuweisung zu verwenden. Bevor Sie zurückkehren, schneiden Sie die Variable ret in eine Länge, die der Anzahl der ausgewählten Elemente entspricht.

Anmerkung 2:

In meinem Beispiel habe ich eine test()-Funktion gewählt, die angibt, ob ein Element zurückgegeben werden soll. Also musste ich Ihre "Ausschlussbedingung" umkehren. Natürlich können Sie die Hilfsfunktion schreiben, um eine Testerfunktion zu erwarten, die angibt, was ausgeschlossen werden soll (und nicht was eingeschlossen werden soll).

26
icza

Schauen Sie sich die Filterbibliothek von robpike an. Dies würde Ihnen Folgendes ermöglichen:

package main

import (
    "fmt"
    "strings"
    "filter"
)

func isNoFoo7(a string) bool {
    return ! strings.HasPrefix(a, "foo_") && len(a) <= 7
}

func main() {
    a := []string{"test", "some_other_test", "foo_etc"}
    result := Choose(a, isNoFoo7)
    fmt.Println(result) // [test]
}

Interessanterweise die README.md von Rob:

Ich wollte sehen, wie schwer es war, diese Art von Go in Go zu implementieren, mit so einer API wie ich es schaffen konnte. Es war nicht schwer . Nachdem ich es vor einigen Jahren geschrieben habe, hatte ich keine Gelegenheit, es einmal zu verwenden. Stattdessen verwende ich einfach "for" -Schleifen . Sie sollten es auch nicht verwenden.

Der idiomatischste Weg laut Rob wäre also:

func main() {
    a := []string{"test", "some_other_test", "foo_etc"}
    nofoos := []string{}
    for i := range a {
        if(!strings.HasPrefix(a[i], "foo_") && len(a[i]) <= 7) {
            nofoos = append(nofoos, a[i])
        }
    }
    fmt.Println(nofoos) // [test]
}

Dieser Stil ist dem Ansatz einer C-Family-Sprache sehr ähnlich, wenn auch nicht identisch.

11
Elwin Arens

Heute bin ich auf eine hübsche Sprache gestoßen, die mich überrascht hat. Wenn Sie ein Slice an Ort und Stelle filtern möchten, ohne es zuzuordnen, verwenden Sie zwei Slices mit demselben Hintergrundarray:

s := []T{
    // the input
} 
s2 := s
s = s[:0]
for _, v := range s2 {
    if shouldKeep(v) {
        s = append(s, v)
    }
}

Hier ist ein spezifisches Beispiel für das Entfernen doppelter Zeichenfolgen:

s := []string{"a", "a", "b", "c", "c"}
s2 := s
s = s[:0]
var last string
for _, v := range s2 {
    if len(s) == 0 || v != last {
        last = v
        s = append(s, v)
    }
}

Wenn Sie beide Segmente aufbewahren müssen, ersetzen Sie einfach s = s[:0] durch s = nil oder s = make([]T, 0, len(s)), je nachdem, ob Sie append() für Sie zuordnen möchten.

3
MicahStetson

Es gibt keine idiomatische Methode, mit der Sie in Go in einer einzigen Zeile dasselbe erwartete Ergebnis erzielen können wie in Ruby. Mit einer Hilfsfunktion können Sie jedoch dieselbe Ausdruckskraft wie in Ruby erzielen. 

Sie können diese Hilfsfunktion wie folgt aufrufen:

Filter(strs, func(v string) bool {
    return strings.HasPrefix(v, "foo_") // return foo_testfor
}))

Hier ist der ganze Code:

package main

import "strings"
import "fmt"

// Returns a new slice containing all strings in the
// slice that satisfy the predicate `f`.
func Filter(vs []string, f func(string) bool) []string {
    vsf := make([]string, 0)
    for _, v := range vs {
        if f(v) && len(v) > 7 {
            vsf = append(vsf, v)
        }
    }
    return vsf
}

func main() {

    var strs = []string{"foo1", "foo2", "foo3", "foo3", "foo_testfor", "_foo"}

    fmt.Println(Filter(strs, func(v string) bool {
        return strings.HasPrefix(v, "foo_") // return foo_testfor
    }))
}

Und das laufende Beispiel: Spielplatz

3
Simo Endre

"Elemente aus Array auswählen" wird auch als filter-Funktion bezeichnet. So etwas gibt es nicht. Es gibt auch keine anderen "Collection-Funktionen" wie "Karte" oder "Verkleinern". Für den idiomatischsten Weg, um das gewünschte Ergebnis zu erzielen, finde ich https://gobyexample.com/collection-functions eine gute Referenz:

[...] in Go ist es üblich, Sammlungsfunktionen bereitzustellen, wenn diese speziell für Ihr Programm und Ihre Datentypen benötigt werden.

Sie bieten ein Implementierungsbeispiel für die Filterfunktion für Strings:

func Filter(vs []string, f func(string) bool) []string {
    vsf := make([]string, 0)
    for _, v := range vs {
        if f(v) {
            vsf = append(vsf, v)
        }
    }
    return vsf
}

Sie sagen jedoch auch, dass es oft in Ordnung ist, die Funktion einfach zu integrieren:

Beachten Sie, dass es in manchen Fällen am klarsten ist, die .__-Datei einfach inline zu integrieren. Code, der Code direkt verarbeitet, anstatt zu erstellen und aufzurufen. eine Helferfunktion.

Im Allgemeinen versucht Golang, nur orthogonale Konzepte einzuführen, was bedeutet, dass, wenn Sie ein Problem auf eine Art lösen können, es nicht zu viele Möglichkeiten gibt, es zu lösen. Dies vereinfacht die Sprache, indem nur wenige Kernkonzepte verwendet werden, sodass nicht jeder Entwickler eine andere Teilmenge der Sprache verwendet.

0
bersling