2016-05-16 3 views
0

У меня есть PartialFunction[String,String] и Map[String,String]. Я хочу применить частичные функции к значениям карты и собрать записи, для которых она была применена. т.е. Дано:Применение частичной функции на поле кортежа, сохранение структуры кортежа

val m = Map("a"->"1", "b"->"2") 
val pf : PartialFunction[String,String] = { 
    case "1" => "11" 
} 

Я хотел бы, чтобы каким-то образом объединить _._2 с pf и быть в состоянии сделать это:

val composedPf : PartialFunction[(String,String),(String,String)] = /*someMagicalOperator(_._2,pf)*/ 
val collected : Map[String,String] = m.collect(composedPf) 
// collected should be Map("a"->"11") 

до сих пор лучшее, что я получил это:

val composedPf = new PartialFunction[(String,String),(String,String)]{ 
     override def isDefinedAt(x: (String, String)): Boolean = pf.isDefinedAt(x._2) 
     override def apply(v1: (String, String)): (String,String) = v1._1 -> pf(v1._2) 
     } 

есть лучший способ?

ответ

3

Вот волшебный оператор:

val composedPf: PartialFunction[(String, String), (String, String)] = 
    {case (k, v) if pf.isDefinedAt(v) => (k, pf(v))} 

Другой вариант, не создавая составленное функции, заключается в следующем:

m.filter(e => pf.isDefinedAt(e._2)).mapValues(pf) 
+0

Это выглядит как лучший способ сделать то, что я сделал, я искал что-то более общее, возможно, даже ootb в стандартной библиотеке. Думая об этом, линзы могут сделать трюк. –

+0

Я понимаю, я тоже пытался найти что-то ootb без успеха. Я сомневаюсь, что есть что-то, потому что вам нужно будет либо написать функции совершенно разных типов: '(String, String) => (String, String)' и 'String => String', или как-то вроде« гнезда »в другой - это то, что делает мой пример. В любом случае, я не могу даже подпись такой функции комбинирования быть отвратительной. – Mifeet

+0

принял ответ. Я обновлю здесь, если найду аккуратный способ добиться этого с помощью линз. –

0

Существует функция в Scalaz, что делает именно то, что: second

scala> m collect pf.second 
res0: scala.collection.immutable.Map[String,String] = Map(a -> 11) 

Это работает, потому что PartialFunction является примером Стрелка (обобщенная функция) typeclass и second - одна из общих операций, определенных для стрелок.

+0

будет ли он работать, если pf был PartialFunction [String, Date]? –

+0

@EyalFarago Конечно. 'second' преобразует стрелку' A => B' в стрелку '(T, A) => (T, B)'. Поэтому он преобразует 'PartialFunction [String, Date]' в 'PartialFunction [(T, String), (T, Date)]'. Если вы используете 'pf.second' непосредственно в' collect', то Scala может определить, что 'T' является' String', но в более сложных случаях вам может потребоваться явно указать 'T', например. 'Pf.second [String]'. – Kolmar