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)
}
Что это будет делать, так это рекурсивно перебирать список кортежей. Проверьте, соответствует ли элемент головы вашему условию (ключевому слову, который вы ищете), а затем возвращает его. Или продолжается с оставшейся частью списка.