2017-10-20 17 views
1

J'ai un Seq[String] dans Scala, et si le Seq contient certains String s, j'ajoute un message pertinent à une autre liste.Scala alternative à la série d'instructions if qui s'ajoutent à une liste?

Existe-t-il une façon plus «scalaesque» de faire cela, plutôt qu'une série d'instructions if qui s'ajoutent à une liste comme ci-dessous?

val result = new ListBuffer[Err]() 

val malformedParamNames = // A Seq[String] 

if (malformedParamNames.contains("$top")) result += IntegerMustBePositive("$top") 
if (malformedParamNames.contains("$skip")) result += IntegerMustBePositive("$skip") 
if (malformedParamNames.contains("modifiedDate")) result += FormatInvalid("modifiedDate", "yyyy-MM-dd") 
... 

result.toList 

Répondre

1

Si vous souhaitez utiliser une scala iterables sucre J'utiliser

sealed trait Err 
case class IntegerMustBePositive(msg: String) extends Err 
case class FormatInvalid(msg: String, format: String) extends Err 

val malformedParamNames = Seq[String]("$top", "aa", "$skip", "ccc", "ddd", "modifiedDate") 

val result = malformedParamNames.map { v => 
    v match { 
    case "$top" => Some(IntegerMustBePositive("$top")) 
    case "$skip" => Some(IntegerMustBePositive("$skip")) 
    case "modifiedDate" => Some(FormatInvalid("modifiedDate", "yyyy-MM-dd")) 
    case _ => None 
    } 
}.flatten 


result.toList 

Soyez avertira si vous demandez chemin scala-esque de faire les choses, il y a beaucoup de possibilités.

La fonction de carte combinée à Aplatir peut être simplifiée en utilisant flatmap

sealed trait Err 
case class IntegerMustBePositive(msg: String) extends Err 
case class FormatInvalid(msg: String, format: String) extends Err 

val malformedParamNames = Seq[String]("$top", "aa", "$skip", "ccc", "ddd", "modifiedDate") 

val result = malformedParamNames.flatMap { 
    case "$top" => Some(IntegerMustBePositive("$top")) 
    case "$skip" => Some(IntegerMustBePositive("$skip")) 
    case "modifiedDate" => Some(FormatInvalid("modifiedDate", "yyyy-MM-dd")) 
    case _ => None 
} 


result 
+0

Merci, se sent comme cela est un peu plus difficile à lire et à comprendre que l'approche originale instruction if bien? – Rory

+0

Je dirais que c'est plus facile à comprendre, mais YMMV. Dans l'approche if-statement, vous devez vous frayer un chemin à travers ce que fait chaque if pour comprendre que vous construisez une séquence basée sur le contenu de l'autre séquence, alors que la présence de map/flatten le rend clair dans Benoît –

+1

Il y a une différence sémantique mineure entre ceci et l'exemple: il n'y aura pas d'éléments répétés dans le code de la question, alors qu'il pourrait y avoir dans cette solution. Si cela est significatif, result.toSet.toList sera déduplé. –

0

Benoit c'est probablement le moyen le plus scala-esque de le faire, mais en fonction de qui va être lire le code plus tard, vous pourriez veux une approche différente.

// Some type definitions omitted 
val malformations = Seq[(String, Err)](
    ("$top", IntegerMustBePositive("$top")), 
    ("$skip", IntegerMustBePositive("$skip")), 
    ("modifiedDate", FormatInvalid("modifiedDate", "yyyy-MM-dd") 
) 

Si vous avez besoin d'une liste et l'ordre est siginificant:

val result = (malformations.foldLeft(List.empty[Err]) { (acc, pair) => 
    if (malformedParamNames.contains(pair._1)) { 
    pair._2 ++: acc // prepend to list for faster performance 
    } else acc 
}).reverse // and reverse since we were prepending 

Si l'ordre est non significatif (bien que si l'ordre est non significatif, vous pourriez envisager de vouloir un ensemble au lieu d'une liste):

val result = (malformations.foldLeft(Set.empty[Err]) { (acc, pair) => 
    if (malformedParamNames.contains(pair._1)) { 
    acC++ pair._2 
    } else acc 
}).toList // omit the .toList if you're OK with just a Set 

Si les prédicats dans les ifs répétées sont plus complexes/moins uniforme, le type de malformation peut-être besoin de changer, comme ils le feraient si les réponses changé, mais le modèle de base est v Etre flexible.

1

La plupart version « scalesque » Je peux penser tout en gardant lisible serait:

val map = scala.collection.immutable.ListMap(
    "$top" -> IntegerMustBePositive("$top"), 
    "$skip" -> IntegerMustBePositive("$skip"), 
    "modifiedDate" -> FormatInvalid("modifiedDate", "yyyy-MM-dd")) 

val result = for { 
    (k,v) <- map 
    if malformedParamNames contains k 
} yield v 

//or 

val result2 = map.filterKeys(malformedParamNames.contains).values.toList