Идиоматический способ преобразования A => Seq [B]
Я хотел бы преобразовать одно значение в коллекцию из нескольких "характеристик", не используя изменяемую структуру данных для сбора значений. Мне хотелось бы что-то вроде этой фантазийной конструкции, которая использует сопоставление образцов, но не останавливается после первого совпадения:
scala> 2 multimatch {
case i if i > 0 => "Positive"
case i if i < 0 => "Negative"
case i if (i % 2 == 0) => "Even"
//yadda yadda
}
res0: Seq[java.lang.String] = List(Positive, Even)
Ответы
Ответ 1
Используя рисунок сутенера, частичные функции и повторяющиеся параметры, вот как я могу получить:
class MultiMatcher[A](a: A) {
def multiMatch[B](pfs: PartialFunction[A, B]*): Seq[B] = {
pfs.map(_.lift(a)).collect{ case Some(v) => v }
}
}
implicit def toMultiMatcher[A](a:A): MultiMatcher[A] = new MultiMatcher(a)
2 multiMatch (
{ case i if i > 0 => "Positive" },
{ case i if i < 0 => "Negative" },
{ case i if i % 2 == 0 => "Even" }
)
// returns Seq[java.lang.String] = ArrayBuffer(Positive, Even)
Ответ 2
Сначала вы определяете свои характеристики как функции из Int в Option [String]
val pos = (i:Int) => if (i > 0) Some("Positive") else None
val neg = (i:Int) => if (i < 0) Some("Negative") else None
val even = (i:Int) => if (i % 2 == 0) Some("Even") else None
Затем вы создадите список характеристик.
val characteristics = pos::neg::even::Nil
И затем вы используете плоскую карту, чтобы получить список тех характеристик, которые относятся к определенному объекту.
scala> characteristics.flatMap(f=>f(2))
res6: List[java.lang.String] = List(Positive, Even)
Ответ 3
Сначала определите функцию multimatch следующим образом:
scala> def multimatch[A,B]( value : A,ps: ( A => Boolean, B)*) =
| for ( p <- ps
| if (p._1(value))) yield p._2
multimatch: [A,B](value: A,ps: ((A) => Boolean, B)*)Seq[B]
Далее, здесь мы идем:
scala> multimatch(2,
| ( ((x :Int) => x > 0) -> "POSITIVE"),
| ( ((x :Int) => x < 0) -> "NEGATIVE"),
| ( ((x :Int) => x % 2 == 0) -> "EVEN")
| )
res4: Seq[java.lang.String] = ArrayBuffer(POSITIVE, EVEN)
Или, менее загроможденный:
scala> multimatch(2,
| ( (x :Int) => x > 0 , "POSITIVE"),
| ( (x :Int) => x < 0, "NEGATIVE"),
| ( (x :Int) => x % 2 == 0, "EVEN")
| )
res5: Seq[java.lang.String] = ArrayBuffer(POSITIVE, EVEN)