Scala - поиск определенного кортежа в списке

Я ударяю головой о стену над этим. (fyi, я еще не scala pro, но я очень люблю это время)

Скажем, у нас есть этот список кортежей:

val data = List(('a', List(1, 0)), ('b', List(1, 1)), ('c', List(0)))

В списке есть эта подпись:

List[(Char, List[Int])]

Моя задача - получить элемент "List [Int]" из кортежа внутри "данных", ключ которого, скажем, например, буква "b".

Другими словами, если я реализую метод типа findIntList (data, 'b') ", то я ожидаю результат List (1, 1)

Чтобы закончить рисунок, я пробовал следующие подходы. Проблема в том, что со всеми подходами (кроме подхода 1, в котором я использую явный "возврат" ), я либо возвращаю объект List[Option] или List[Any], который я не знаю, как извлечь "List[Int]" из

Подход 1:

data.foreach { elem => if (elem._1 == char) return elem._2 }

Подход 2:

data.find(x=> x._1 == ch)

Подход 3:

for (elem <- data) yield elem match {case (x, y: List[Bit]) => if (x == char) y}

Подход 4:

for (x <- data) yield if (x._1 == char) x._2

Ответ 1

Один из многих способов:

data.toMap.get('b').get

toMap преобразует список 2-кортежей в Map из первого элемента кортежей во второй. get дает вам значение для данного ключа и возвращает Option, поэтому вам нужен еще один get, чтобы получить список.

Или вы можете использовать:

data.find(_._1 == 'b').get._2 

Примечание. Используйте только кнопку Option, если вы можете гарантировать, что у вас будет Some, а не None. См. http://www.scala-lang.org/api/current/index.html#scala.Option для использования опции idiomatic.

Обновление: Объяснение типов результатов, которые вы видите с помощью разных подходов

Подход 2: find возвращает параметр [Список [Int]], потому что он не может гарантировать, что найден соответствующий элемент.

Подход 3: здесь вы в основном делаете Map, т.е. применяете функцию к каждому элементу своей коллекции. Для элемента, который вы ищете, функция возвращает ваш List [Int] для всех других элементов, в котором содержится значение (), которое является значением Unit, примерно эквивалентным void в Java, но фактическим типом. Поскольку единственный общий супер-тип'List [Int] 'и'Unit' - 'Any', вы получаете результат 'List [Any]'.

Подход 4 в основном такой же, как # 3

Ответ 2

Другой способ -

data.toMap.apply('b')

Или с одним промежуточным шагом это еще лучше:

val m = data.toMap
m('b')

где apply используется неявно, т.е. последняя строка эквивалентна

m.apply('b')

Ответ 3

Существует несколько способов сделать это. Еще один способ:

scala> def listInt(ls:List[(Char, List[Int])],ch:Char) = ls filter (a => a._1 == ch) match {
 | case Nil => List[Int]()
 | case x ::xs => x._2
 | }
listInt: (ls: List[(Char, List[Int])], ch: Char)List[Int]
scala> listInt(data, 'b')
res66: List[Int] = List(1, 1)

Ответ 4

Вы можете попробовать что-то вроде (когда вы уверены, что оно существует) просто добавив информацию о типе.

val char = 'b'
data.collect{case (x,y:List[Int]) if x == char => y}.head

или используйте headOption, если вы не уверены, что символ существует

data.collect{case (x,y:List[Int]) if x == char => y}.headOption

Ответ 5

Вы также можете решить эту проблему с помощью сопоставления с образцом. Имейте в виду, что вам нужно сделать его рекурсивным. Решение должно выглядеть примерно так:

def findTupleValue(tupleList: List[(Char, List[Int])], char: Char): List[Int] = tupleList match {
  case (k, list) :: _ if char == k => list
  case _ :: theRest => findTupleValue(theRest, char)
}

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