2017-01-23 1 views
0

J'ai écrit ma propre définition récursive d'un foldLeft et je voudrais l'utiliser avec cette fonction joinTerminateLeft qui prend une liste de chaînes et un terminateur et crée une nouvelle chaîne avec ceux chaînes toutes séparées par le terminateur.Scala en utilisant foldLeft pour insérer le terminateur entre la liste des chaînes

Par exemple List("a", "b", "c", "d") avec terminaison ; finirait par être a;b;c;d;

Voici mon foldLeft que je pense est très bien, mais mon terminateLeft ne fonctionne pas pour une raison étrange, une idée?

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) 
    } 
} 

Quand je lance joinTerminateLeft a, b, c, d, il arrête après B pour une raison quelconque et sort les chaînes c, d, mais pas avec la terminaison.

+0

Donc c'est une pratique? Parce que 'mkString ("; ")' fonctionne parfaitement bien. – Psidom

+0

Oui, c'est pour l'entraînement. Je dois accomplir joinTerminateLeft en utilisant mon foldLeft sans aucune méthode supplémentaire à part la concaténation de chaîne que je suppose nécessaire. – mocode9

+0

De plus, je ne pense pas que 'foldLeft' soit la bonne fonction pour cela, car ici vous n'avez pas besoin d'une valeur initiale pour rejoindre la liste sous forme de chaîne. Une fonction avec une signature similaire de 'reduce' pourrait être mieux adaptée. – Psidom

Répondre

1

Qu'est-ce qui se passe, c'est que vous utilisez terme comme valeur de départ. Mais e est un accumulateur, chaque itération ajoute sur le dernier. Donc, passez une fois, et vous obtenez ; + b mais la prochaine fois que l'accumulateur est la valeur de ce que vous obtenez |b + c

Ce dont vous avez besoin est une fonction différente. Au lieu d'ajouter la valeur à l'accumulateur, vous devez ajouter un terme à la valeur, puis l'ajouter à l'accumulateur.

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

Merci pour la suggestion, mais si appelé avec une liste d'un seul paramètre, il ne semble pas fonctionner. assert (joinTerminateLeft (List ("a"), ";") === "a;") Cela retourne juste "a" une idée? – mocode9

+0

La façon dont il est actuellement, il va mettre un délimiteur entre les valeurs, lorsqu'il n'y a qu'une seule valeur, il n'y a pas d'espace "entre" pour mettre un délimiteur. Si vous voulez simplement entrer la valeur après chaque chaîne, changez votre fonction pour mettre le terme à la fin d'une chaîne au lieu du début 's2 + s3 + s' Et au lieu de passer seulement la queue à foldLeft et en ajoutant la tête sur Après, appliquez foldLeft à la liste entière. – puhlen

+0

Nice! Ça a marché! – mocode9

0

Voici un extrait qui fonctionne:

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) 
    } 
} 

Le terme ne doit être utilisé à l'intérieur f. Le second paramètre de foldLeft est la valeur d'initialisation qui devrait être vide dans ce cas (réduire ou quelque chose de similaire serait plus approprié au lieu de se replier ici).