Scala - преобразовать массив [String] в массив [Double]

Я новичок в функциональном языке программирования, и я изучаю его в Scala для университетского проекта.

Это может показаться простым, но я не могу найти достаточную помощь в Интернете для этого или простого способа сделать это - как я могу преобразовать Array [String] в Array [Double]? У меня есть файл CSV, который при чтении в REPL интерпретируется как значения String (каждая строка файла содержит сочетание целых и строковых значений), которые возвращают тип Array [String]. Я хочу кодировать строковые значения с помощью значений double/int, чтобы вернуть Array [Double], чтобы сделать массив однородным. Есть ли простой способ сделать это? Любые рекомендации будут высоко оценены.

Что я сделал до сих пор:

def retrieveExamplesFromFile(fileName : String) : Array[Array[String]] = {
  val items = for {
    line <- Source.fromFile(fileName).getLines()
    entries = line.split(",")
    } yield entries

  return items.toArray
}

Формат каждой строки (возвращаемый как String []):

[[1.0, 2.0, item1], [5, 8.9, item2],....]

И чтобы преобразовать каждую строку в CSV файл в двойной массив, у меня есть только определение psuedo, поэтому:

def generateNumbersForStringValues(values : Array[String]) : Array[Double] = {
val line = for(item <- values)
{
    //correct way?
    item.replace("item1", "1.0")
    item.replace("item2", "1.0")    
} 
return //unable to typecast/convert
}

Любые идеи приветствуются. Спасибо за ваше время.

Ответ 1

Вероятно, вы хотите использовать map вместе с toDouble:

values.map(x => x.toDouble)

Или более кратко:

values.map(_.toDouble)

И для возврата для недвойных строк вы можете использовать монаду Tryscala.util):

values.map(x => Try(x.toDouble).getOrElse(1.0))

Если вы знаете, как будет выглядеть каждая строка, вы также можете выполнить сопоставление с образцом:

values map { 
    case Array(a, b, c) => Array(a.toDouble, b.toDouble, 1.0)
}

Ответ 2

Вы хотите преобразовать все строки в double с резервными значениями в 1.0 для всех необратимых строк? Это будет:

val x = Array(
  Array("1.0", "2.0", "item1"),
  Array("5", "8.9", "item2"))

x.map( _.map { y =>
  try {
    y.toDouble
  } catch {
    case _: NumberFormatException => 1.0
  }
})

Ответ 3

Развернув комментарий @DaunnC, вы можете использовать утилиту Try, чтобы сделать это, и совпадение шаблонов в результате, чтобы избежать вызова get или переноса результата в Option:

import scala.util.{Try, Success, Failure}

def main = {
  val maybeDoubles = Array("5", "1.0", "8.5", "10.0", "item1", "item2")

  val convertDoubles = maybeDoubles.map { x =>
    Try(x.toDouble)
  }

  val convertedArray = convertDoubles.map {
    _ match {
      case Success(res) => res
      case Failure(f) => 1.0
   }
  }

  convertedArray
}

Это позволяет сопоставлять шаблон по результату Try, который всегда является либо Success, либо Failure, без необходимости называть get или иначе обертывать ваши результаты.

Ниже приведена дополнительная информация о Try любезно предоставлена ​​Маурисио Линаресом: https://mauricio.github.io/2014/02/17/scala-either-try-and-the-m-word.html

Ответ 4

Scala 2.13 представляет String::toDoubleOption который используется в преобразовании map, может быть связан с Option::getOrElse для безопасного приведения String в Double s:

Array("5", "1.0", ".", "8.5", "int").map(_.toDoubleOption.getOrElse(1d))
// Array[Double] = Array(5.0, 1.0, 1.0, 8.5, 1.0)