Можно ли сопоставить диапазон в Scala?

Можно ли сопоставить диапазон значений в Scala?

Например:

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

m было бы true, если бы t было между 0 и 10, в противном случае было бы ложно. Это немного не работает, конечно, но есть ли способ добиться чего-то подобного?


person Justin Poliey    schedule 28.08.2009    source источник
comment
Обратите внимание, что, записывая от 0 до 10, вы имеете в виду 0, 1, 2, ..., 9 (включая 0, исключая 10). Если вы хотите включить 10, используйте от 0 до 10.   -  person Jesper    schedule 28.08.2009
comment
См. связанный с этим вопрос о стеке: Как я могу сопоставить шаблон на диапазон в Scala?   -  person David J.    schedule 26.09.2011
comment
В заголовке спрашивается, как сопоставить значение типа Range с несколькими возможностями, например. У меня есть (0..5) или (1..6)?   -  person Raphael    schedule 26.09.2011
comment
val m = 0 until 10 contains t фактически то же самое, но короче. это даст вам истинный/ложный ответ. Если логический ответ - это все, что вам нужно.   -  person Peter Perháč    schedule 14.05.2017


Ответы (5)


Охрана с помощью Range:

val m = t match {
  case x if 0 until 10 contains x => true
  case _ => false
}
person Alexander Azarov    schedule 28.08.2009
comment
а как же Дабл? 0,1 и 10,0 - person Oleg Abrazhaev; 19.06.2018
comment
@OlegAbrazhaev в чем дело? - person Alexander Azarov; 19.06.2018
comment
@AlexanderAzarov как это реализовать? Не могли бы вы добавить пример для двойников? Шаг будет 0,1, а не 1. - person Oleg Abrazhaev; 20.06.2018
comment
@OlegAbrazhaev в REPL: scala> 0.0 until 10.0 by 0.1 contains 4.0 возвращает res0: Boolean = true - person Alexander Azarov; 20.06.2018

Вы можете использовать охранников:

val m = t match {
    case x if (0 <= x && x < 10) => true
    case _ => false
}
person Alexey Romanov    schedule 28.08.2009
comment
С точки зрения производительности это решение лучше, чем решение @alexander-azarov. Там диапазон необходимо инициализировать, а затем выполнить сканирование диапазона. Особенно для больших диапазонов это может стать проблемой. - person Oosterman; 20.05.2016
comment
Range.contains, конечно же, переопределяется, поэтому ему не нужно ничего сканировать! Это все еще немного лишнего кода, но Hotspot без проблем встроит и оптимизирует его. - person Alexey Romanov; 20.05.2016

С этими определениями:

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

Вы можете сделать такие проверки:

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

Итак, код, который вам нужен, будет:

val m = x in (0 to 10)
person Wilfred Springer    schedule 26.09.2014

Вот еще один способ сопоставления с использованием диапазона:

val m = t match {
  case x if ((0 to 10).contains(x)) => true
  case _ => false
}
person swartzrock    schedule 02.07.2012
comment
Это дублирует ответ @Alexander Azarov. - person Glenn; 12.02.2015
comment
Неверное совпадение для t == 10. - person Alexander Prokofyev; 23.09.2016

Другим вариантом было бы добавить это к языку, используя неявные значения, я добавил два варианта для int и Range.

object ComparisonExt {
  implicit class IntComparisonOps(private val x : Int) extends AnyVal {
    def between(range: Range) = x >= range.head && x < range.last
    def between(from: Int, to: Int) = x >= from && x < to
  }

}

object CallSite {
  import ComparisonExt._

  val t = 5
  if (t between(0 until 10)) println("matched")
  if (!(20 between(0 until 10))) println("not matched")
  if (t between(0, 10)) println("matched")
  if (!(20 between(0, 10))) println("not matched")
}
person Noam    schedule 01.04.2018