2009-08-28 5 views
39

Est-il possible de faire correspondre une plage de valeurs dans Scala?Peut-on associer une gamme à Scala?

Par exemple:

val t = 5 
val m = t match { 
    0 until 10 => true 
    _ => false 
} 

m serait true si t était entre 0 et 10, mais sinon false. Ce petit bout ne fonctionne pas bien sûr, mais est-il possible de réaliser quelque chose comme ça?

+3

Notez que par écrit "0 jusqu'à 10" vous voulez dire 0, 1, 2,. .., 9 (y compris 0, sauf 10). Si vous voulez inclure 10, utilisez "0 à 10". – Jesper

+0

Voir une question de stackoverflow connexe: [Comment est-ce que je peux faire correspondre un motif sur une plage de Scala?] (Http://stackoverflow.com/questions/3160888/how-can-i-pattern-match-on-a-range-in -scala) –

+0

Le titre demande comment faire correspondre une valeur de type 'Range' avec plusieurs possibilités, par ex. "Est-ce que j'ai' (0.5) 'ou' (1..6) '?" – Raphael

Répondre

65

Garde à l'aide Range:

val m = t match { 
    case x if 0 until 10 contains x => true 
    case _ => false 
} 
+0

C'est très intelligent! Pour une raison quelconque, je n'ai jamais pensé à le faire de cette façon ... –

27

Vous pouvez utiliser des gardes:

val m = t match { 
    case x if (0 <= x && x < 10) => true 
    case _ => false 
} 
+0

En termes de performance, cette solution est meilleure que la solution @ alexander-azarov. Là, la gamme doit être initialisée suivie d'un balayage de gamme. Surtout pour les grandes distances, cela peut devenir un problème. – Oosterman

+1

'Range.contains' est bien sûr surchargé donc il n'a pas besoin de scanner quoi que ce soit! C'est encore un peu de code supplémentaire, mais Hotspot devrait l'intégrer et l'optimiser sans problème. –

2

Voici une autre façon de correspondre à l'aide d'une gamme:

val m = t match { 
    case x if ((0 to 10).contains(x)) => true 
    case _ => false 
} 
+0

Cela reproduit la réponse de @Alexander Azarov. – Glenn

+0

Mauvaise correspondance pour t == 10. –

2

Avec ces définitions:

trait Inspector[-C, -T] { 
    def contains(collection: C, value: T): Boolean 
    } 

    implicit def seqInspector[T, C <: SeqLike[Any, _]] = new Inspector[C, T]{ 
    override def contains(collection: C, value: T): Boolean = collection.contains(value) 
    } 

    implicit def setInspector[T, C <: Set[T]] = new Inspector[C, T] { 
    override def contains(collection: C, value: T): Boolean = collection.contains(value) 
    } 

    implicit class MemberOps[T](t: T) { 
    def in[C](coll: C)(implicit inspector: Inspector[C, T]) = 
     inspector.contains(coll, t) 
    } 

Vous pouvez faire des tests comme ceux-ci:

2 in List(1, 2, 4)  // true 
2 in List("foo", 2)  // true 
2 in Set("foo", 2)  // true 
2 in Set(1, 3)   // false 
2 in Set("foo", "foo") // does not compile 
2 in List("foo", "foo") // false (contains on a list is not the same as contains on a set) 
2 in (0 to 10)   // true 

Ainsi, le code dont vous avez besoin serait:

val m = x in (0 to 10) 
Questions connexes