Использование filterNot с картой

#scala

#scala

Вопрос:

У меня есть простая карта

 val m = Map("a1" -> "1", "b2" -> "2", "c3" -> "3")
val someList = List("b", "d")
m.filterNot( (k,v) => someList.exist(l => k.startsWith(l)) )
  

Я получаю сообщение об ошибке:

 error: missing parameter type
  

Я уверен, что я делаю здесь что-то глупое, почему это не компилируется?

Ответ №1:

filterNot требуется case ключевое слово и {} при извлечении k, v из кортежа.

обратите внимание, что exist это не его exists

 m.filterNot { case (k,v) => someList.exists(l => k.startsWith(l)) }
  

или

 m.filterNot(pair => someList.exists(l => pair._1.startsWith(l)))
  

Объяснение

Поскольку вы извлекаете k, v из кортежа, используя синтаксис экстрактора, вы должны использовать case ключевое слово и {}

Без синтаксиса экстрактора вы можете сделать

 m.filterNot(pair => someList.exists(l => pair._1.startsWith(l)))
  

Scala REPL

 scala> val m = Map("a1" -> "1", "b2" -> "2", "c3" -> "3")
m: scala.collection.immutable.Map[String,String] = Map(a1 -> 1, b2 -> 2, c3 -> 3)

scala> val someList = List("b", "d")
someList: List[String] = List(b, d)

scala>  m.filterNot { case (k,v) => someList.exists(l => k.startsWith(l)) }
res15: scala.collection.immutable.Map[String,String] = Map(a1 -> 1, c3 -> 3)
  

Без синтаксиса экстрактора

Теперь вам не нужно использовать case ключевое слово и {} , поскольку мы не используем извлечение ключа и значения с использованием синтаксиса экстрактора

 scala> m.filterNot(pair => someList.exists(l => pair._1.startsWith(l)))
res18: scala.collection.immutable.Map[String,String] = Map(a1 -> 1, c3 -> 3)

scala> val m = Map("a1" -> "1", "b2" -> "2", "c3" -> "3")
m: scala.collection.immutable.Map[String,String] = Map(a1 -> 1, b2 -> 2, c3 -> 3)

scala> val someList = List("b", "d")
someList: List[String] = List(b, d)

scala> m.filterNot(pair => someList.exists(l => pair._1.startsWith(l)))
res19: scala.collection.immutable.Map[String,String] = Map(a1 -> 1, c3 -> 3)
  

Комментарии:

1. Или просто: (pair => someList.exists(pair._1.startsWith))

2. Хм, я этого не вижу. Все ваши примеры передают l параметр явно: startsWith(l) на самом деле его можно уменьшить еще больше, m.filterNot(someList exists _._1.startsWith) , но теперь мы рискуем скрыть код, будучи слишком милыми с синтаксисом.

Ответ №2:

Проблема заключается в следующем: filterNot метод принимает один параметр, в то время как вы определяете список из двух параметров. Это сбивает с толку компилятор, и это сообщение является результатом.

Чтобы решить эту проблему, вы можете использовать следующий синтаксис (обратите внимание на использование сопоставления с шаблоном с case ключевым словом):

 m.filterNot { case (k,v) => someList.exist(l => k.startsWith(l)) }
  

Использование сопоставления с шаблоном, подобное этому, создает a PartialFunction , который будет разлагать ключ и значение и применяться как обычная функция к вашему Map .

Комментарии:

1. Обратите внимание, что, поскольку вы не используете значение, вы можете отказаться от значения, используя _ подобное: m.filterNot { case (k, _) => someList.exist(l => k.startsWith(l)) }

2. В какой-то момент в будущем это раздражение будет устранено, согласно создателю языка Мартину Одерски: youtu.be/_2oGY8l67jk?t=34m50s

Ответ №3:

Использование синтаксиса для понимания, извлечения и фильтрации может быть достигнуто следующим образом,

 for ( pair@(k,v) <- m; l <- someList if !k.startsWith(l)) yield pair