web-dev-qa-db-fra.com

Scala - convertit un tableau [chaîne] en un tableau [double]

Je suis un novice en langage de programmation fonctionnel et je l’apprends à Scala pour un projet universitaire. 

Cela peut sembler simple, mais je ne parviens pas à trouver assez d'aide en ligne pour cela ni pour un moyen simple de procéder. Comment convertir un Array [String] en Array [Double]? J'ai un fichier CSV qui, lorsqu'il est lu dans le REPL, est interprété comme des valeurs de chaîne (chaque ligne du fichier contient un mélange de valeurs d'entier et de chaîne) qui renverrait un type Array [String]. Je veux encoder les valeurs de chaîne avec des valeurs double/int pour renvoyer Array [Double] afin de rendre le tableau homogène. Y at-il un moyen simple de faire cela? Toute orientation sera très appréciée.

Ce que j'ai fait jusqu'à présent c'est:

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

  return items.toArray
}

Le format de chaque ligne (renvoyé sous forme de chaîne []) est le suivant:

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

Et pour convertir chaque ligne du fichier CSV en tableau double, je ne dispose que d’une définition 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
}

Toutes les idées sont les bienvenues. Merci pour votre temps.

14
Sharadha Jayaraman

Vous voulez probablement utiliser map avec toDouble:

values.map(x => x.toDouble)

Ou plus concement:

values.map(_.toDouble)

Et pour la solution de secours pour les chaînes non doubles, vous pouvez envisager d'utiliser le monad Try (en scala.util):

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

Si vous savez à quoi ressemblera chaque ligne, vous pouvez également rechercher des motifs:

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

En développant le commentaire de @ DaunnC, vous pouvez utiliser l'utilitaire Try pour le faire et appliquer une correspondance de motif au résultat afin d'éviter d'appeler get ou de placer votre résultat dans un 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
}

Cela vous permet de rechercher une correspondance de motif sur le résultat de Try, qui est toujours soit un Success ou un Failure, sans avoir à appeler get ou à envelopper vos résultats.

Voici quelques informations supplémentaires sur Try, offert par Mauricio Linhares: https://mauricio.github.io/2014/02/17/scala-either-try-and-the-m-W-ord.html

3
Joseph Sawyer

Vous voulez convertir toutes les chaînes avec un repli à 1.0 pour toutes les chaînes non convertibles? Ce serait:

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
Lodewijk Bogaards

Scala 2.13 introduit String::toDoubleOption utilisé dans une transformation map, peut être associé à Option::getOrElse pour convertir en toute sécurité Strings en Doubles:

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