2009-08-28 8 views
39

È possibile abbinare un intervallo di valori in Scala?È possibile abbinare un intervallo in Scala?

Ad esempio:

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

m sarebbe true se t era tra 0 e 10, ma altrimenti false. Questo poco non funziona ovviamente, ma esiste un modo per ottenere qualcosa di simile?

+3

noti che scrivendo "0 fino al 10" intendi 0, 1, 2,. .., 9 (compreso 0, escluso 10). Se si desidera includere 10, utilizzare "0 a 10". – Jesper

+0

Vedere una domanda di stackoverflow correlata: [Come posso eseguire lo schema di corrispondenza su un intervallo in Scala?] (Http://stackoverflow.com/questions/3160888/how-can-i-pattern-match-on-a-range-in -scala) –

+0

Il titolo chiede come abbinare un valore di tipo 'Range' a diverse possibilità, ad es. "Ho' (0..5) 'o' (1..6) '?" – Raphael

risposta

65

Guardia utilizzando Range:

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

È molto intelligente! Per qualche ragione, non ho mai pensato di farlo in questo modo ... –

27

È possibile utilizzare guardie:

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

In termini di prestazioni questa soluzione è migliore della soluzione @ alexander-azarov. Qui è necessario inizializzare l'intervallo seguito da una scansione dell'intervallo. Soprattutto per le grandi gamme questo può diventare un problema. – Oosterman

+1

'Range.contains' è ovviamente sovrascritto quindi non è necessario eseguire la scansione di nulla! È ancora un po 'di codice in più, ma Hotspot dovrebbe essere in linea e ottimizzarlo senza problemi. –

2

Ecco un altro modo per abbinare con un intervallo:

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

Questo duplica la risposta di @Alexander Azarov. – Glenn

+0

Corrispondenza errata per t == 10. –

2

Con queste definizioni:

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

Si può fare controlli come questi:

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 

Quindi il codice necessario sarebbe:

val m = x in (0 to 10) 
Problemi correlati