10
votes

Scala: motif correspondant lorsque l'un des deux éléments rencontre une condition

Je suis souvent en train d'écrire du code qui compare deux objets et produit une valeur sur la base de leur identique, ou différente, sur la base de la manière dont elles sont différentes.

Donc, je pourrais écrire: P>

class OneAndOnlyOne[T](predicate: T => Boolean) {
  def unapply( pair: Pair[T,T] ): Option[T] = {
    val (item1,item2) = pair
    val v1 = predicate(item1)
    val v2 = predicate(item2)

    if ( v1 != v2 )
      Some( if ( v1 ) item1 else item2 )
    else
      None
  }
}


3 commentaires

Avez-vous un cas d'utilisation indiquant pourquoi vous voulez faire cela? Peut-être qu'une meilleure solution existe à l'aide de soit


Cas d'utilisation - surtout je veux juste éviter d'écrire les deux cas par ex. (certains, aucun) et (aucun, certains). Mon cas d'utilisation générale est que je comparais deux produits sur une caractéristique particulière, et peut-être que les deux produits ont la caractéristique, ou seulement l'un d'entre eux, ou s'ils l'ont tous deux, peut-être que l'on a une bonne valeur pour cette caractéristique et un pauvre valeur.


Dupliqué possible de Match de plusieurs classes de cas dans Scala


6 Réponses :


6
votes

Que diriez-vous de cela:

    Welcome to Scala version 2.8.0.r20327-b20091230020149 (Java HotSpot(TM) Client VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def m(v1: Any,v2: Any) = (v1,v2) match {
     |     case (Some(x),Some(y)) => "a"
     |     case (Some(_),None) | (None,Some(_)) => "b"
     |     case _ => "c"
     | }
m: (v1: Any,v2: Any)java.lang.String

scala> m(Some(1),Some(2))
res0: java.lang.String = a

scala> m(Some(1),None)
res1: java.lang.String = b

scala> m(None,None)
res2: java.lang.String = c

scala>


1 commentaires

Cela semble assez simple, je pense que j'ai essayé cela à Scala 2.7 et cela ne compila pas, je vais essayer à nouveau.



4
votes

Vous devriez pouvoir le faire si vous le définissez en tant que Val d'abord: xxx

comme indiqué par le nom, le nom du VAL contenant l'objet extracteur doit être capitalisé. < / p>


2 commentaires

Expressions régulières comme des cas sont utilisés de la même manière.


Merci Mitch, j'ai fait en fait essayer cela, et je pense que cela a échoué parce que je n'avais pas mon Val capitalisé .. intéressant.



19
votes

Je pense que vous posez deux questions légèrement différentes.

Une question est de savoir comment utiliser "ou" dans les relevés de commutation. || ne fonctionne pas; | Est-ce que. Et vous ne pouvez pas utiliser de variables dans ce cas (car en général, ils peuvent correspondre à différents types, ce qui rend le type déroutant). Donc: P>

class DiOption[+T] {
  def trinary = this
}
case class Both[T](first: T, second:T) extends DiOption[T] { }
case class OneOf[T](it: T) extends DiOption[T] { }
case class Neither() extends DiOption[Nothing] { }
implicit def sometuple2dioption[T](t2: (Option[T],Option[T])): DiOption[T] = {
  t2 match {
    case (Some(x),Some(y)) => Both(x,y)
    case (Some(x),None) => OneOf(x)
    case (None,Some(y)) => OneOf(y)
    case _ => Neither()
  }
}

// Example usage
val a = (Some("This"),None)
a trinary match {
  case Both(s,t) => "Both"
  case OneOf(s) => "Just one"
  case _ => "Nothing"
}


3 commentaires

Salut Rex, qui semble prometteur, mais cela ne s'étend pas (encore) à d'autres situations, par exemple. Là où on ne demande pas l'un d'entre eux d'être défini, mais pour que l'un d'entre eux de dire "soit un nombre uniforme" ou "avoir une valeur> 10".


Ne: pas: cas (certains (x), certains (y)) si ((x> 10) && (y iseven)) => "les deux" travail?


Je ne suis pas sûr que je suive Jim, mais: Oui, cela fonctionne, mais je ne pense pas que ce que je dis. J'aimerais conceptuellement faire ceci: cas (OneEven) => cas (BotteEeven) =>. Par exemple. Qu'ils soient même ou non, c'est juste un test différent de savoir s'il n'est pas à la fois ou non pas aucun.



3
votes

sur SCALAA 2.8:

val result = (List(v1,v2).flatten : List[Int]) match {
  case List(value1, value2) => "a"
  case List(value) => "b"
  case _ = > "c"
}


5 commentaires

Merci pour la réponse Daniel, qui semble bien mais ne fonctionne que pour le prédicat "x => x.isdefinefin", je ne pouvais pas l'utiliser pour dire "x => x% 2 == 0" pour vérifier si un seul et un seul des deux articles était même.


@Alex - Vous pouvez l'exprimer comme ceci: Liste (V1, V2) Filtre (_% 2 == 0) Match {Liste des cas (Valeur1, Value2) => "A" Liste de cas (valeur) => " b "cas _ =>" c "}


Filtrer la liste en premier. Je pense que la solution de Daniel est la plus étroite en avant.


@ALEX: Je suppose que vous pouvez extraire le modèle: def xmatch (valeurs: liste [T], F: T => Boolean, P: liste [Partialfunction [T, X]]) .


@ALEX: J'ai un peu bricolé avec un peu: Stackoverflow.com/Questtions/2039715/...



7
votes

Si vous devez prendre en charge des prédicats arbitraires, vous pouvez en dériver de ceci (qui est basé sur L'idée de Daniel ): xxx

la définition de la fonction: xxx

Maintenant, vous pouvez l'utiliser comme ceci: xxx

Je ne suis pas si sûr si c'est une bonne idée (c'est-à-dire lisible). Mais un exercice soigné néanmoins.

Ce serait bien si vous pouviez correspondre à des tuples: cas (valeur1, valeur2) => ... au lieu de listes.


1 commentaires

Homme, j'aime Scala. Il ne pouvait pas être plus lisible, et c'est une fonction . Et une doublure, à cela.



0
votes

Depuis que vous avez déjà assorté contre (certains (x), certains (y), vous pouvez correspondre à (aucun, aucun) explicitement, et les cas restants sont (certains (x), aucun) et (aucun, certains ( y)):

def decide [T](v1: Option[T], v2:Option[T]) = (v1, v2) match {
  case (Some (x), Some (y)) => "a"
  case (None, None)         => "c"
  case _                    => "b"
}

val ni : Option [Int] = None 
decide (ni, ni)            // c
decide (Some (4), Some(3)) // a
decide (ni, Some (3))      // b
decide (Some (4), ni)      // b


0 commentaires