2017-01-23 2 views
0

Ich schrieb meine eigene rekursive Definition eines foldLeft und ich würde es mit dieser Funktion joinTerminateLeft verwenden, die eine Liste von Zeichenfolgen und einem Terminator und erstellt eine neue Zeichenfolge mit denen Strings alle durch den Terminator getrennt.Scala mit foldLeft zum Einfügen Terminator zwischen der Liste der Strings

Zum Beispiel List("a", "b", "c", "d") mit Terminator ;a;b;c;d;

hier am Ende als würde mein foldLeft was ich denke, ist in Ordnung, aber meine terminateLeft nicht aus irgendeinem Grunde arbeitet, jede Idee?

def foldLeft [A,B] (xs:List[A], e:B, f:(B,A)=>B) : B = { 
    def auxFoldLeft(xs: List[A], e: B) : B = { 
    xs match { 
     case Nil => e 
     case x::xs => auxFoldLeft(xs, f(e, x)) 
    } 
    } 
    auxFoldLeft(xs, e) 
} 

def joinTerminateLeft (xs : List[String], term : String) : String = { 
    def f(s: String, s2: String) : String = s + s2 
    xs match { 
    case Nil => "" 
    case x::xs => x + foldLeft(xs, term, f) 
    } 
} 

Wenn ich laufe joinTerminateLeft mit a, b, c, d es aus irgendeinem Grunde nach B stoppt und gibt die Saiten c, d, aber nicht mit dem Terminator.

+0

Das ist also eine Praxis? Denn 'mkString ("; ")' funktioniert einwandfrei. – Psidom

+0

Ja, es ist für die Praxis. Ich muss joinTerminateLeft mit meinem foldLeft durchführen, ohne zusätzliche Methoden neben der String-Verkettung, von der ich annehme, dass es notwendig ist. – mocode9

+0

Plus Ich glaube nicht, dass 'foldLeft' die richtige Funktion dafür ist, denn hier brauchst du keinen Anfangswert, um die Liste als String zu verbinden. Eine Funktion mit ähnlicher Signatur von "reduce" könnte besser geeignet sein. – Psidom

Antwort

1

Was passiert ist, dass Sie Begriff als Startwert verwenden. Aber e ist ein Akkumulator, jede Iteration addiert sich zu der letzten. So gehen Sie einmal durch, und Sie erhalten ; + b, aber das nächste Mal der Akku ist der Wert von dem, so erhalten Sie |b + c

Was Sie brauchen, ist eine andere Funktion. Anstatt den Wert zum Akkumulator hinzuzufügen, müssen Sie dem Wert einen Term hinzufügen und ihn dann zum Akkumulator hinzufügen.

def joinTerminateLeft (xs : List[String], term : String) : String = { 
    def f(s: String)(s2: String, s3: String) : String = s2 + s + s3 
    xs match { 
    case Nil => "" 
    case x::xs => x + foldLeft(xs, "", f(term)) 
    } 
} 
+0

Danke für den Vorschlag, aber wenn er mit einer Liste von nur einem Parameter aufgerufen wird, scheint es nicht zu funktionieren. assert (joinTerminateLeft (Liste ("a"), ";") === "a;") Dies ergibt nur "a" irgendeine Idee? – mocode9

+0

Wie es derzeit ist, wird es ein Trennzeichen zwischen den Werten setzen, wenn es nur einen Wert gibt, gibt es keinen "dazwischen" Platz, um ein Trennzeichen zu setzen. Wenn Sie den Wert einfach nach jeder Zeichenfolge eingeben möchten, ändern Sie Ihre Funktion so, dass der Ausdruck am Ende einer Zeichenfolge anstelle des Anfangs "s2 + s3 + s" steht und nicht nur der Schwanz zu foldLeft übergeht und den Kopf anfügt Danach wenden Sie foldLeft einfach auf die gesamte Liste an. – puhlen

+0

Schön! Das hat funktioniert! – mocode9

0

Hier ist ein Ausschnitt, das funktioniert:

def joinTerminateLeft (xs : List[String], term : String) : String = { 
    def f(s: String, s2: String) : String = s + term + s2 
    xs match { 
     case Nil => "" 
     case x::xs => x + foldLeft(xs, "", f) 
    } 
} 

Der Begriff nur innerhalb f verwendet werden soll. Der zweite Parameter von foldLeft ist der Initialisierungswert, der in diesem Fall leer sein sollte (reduzieren oder etwas Ähnliches wäre besser geeignet als hier links).

Verwandte Themen