Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I have the following snippets. This first solution uses <code>groupBy</code> to group the entrances related to the same station. It does not assume that rows are sorted. Although it reads the file only once, it really does 3 passes (one to read all in memory, one for <code>groupBy</code> and one to create the stations). See at the end for the code for the <code>Row</code> extractor.</p> <pre><code>val stations = { val file = new java.io.File("StationEntrances.csv") val reader = com.github.tototoshi.csv.CSVReader.open(file) val byStation = reader .all // read all in memory .drop(1) // drop header .groupBy { case List(division, line, station, _*) =&gt; (division, line, station) } reader.close byStation.values.toList map { rows =&gt; val entrances = rows map { case Row(_, _, _, _, entrance) =&gt; entrance } rows.head match { case Row(division, line, station, routes, _) =&gt; Station( division, line, station, routes.toList.filter(_ != ""), entrances) } } } </code></pre> <p>This solution assumes that the rows are sorted and should be faster, as it does only one pass and build the result list as it reads the file. </p> <pre><code>val stations2 = { import collection.mutable.ListBuffer def processByChunk(iter: Iterator[Seq[String]], acc: ListBuffer[Station]) : List[Station] = { if (!iter.hasNext) acc.toList else { val head = iter.next val marker = head.take(3) val (rows, rest) = iter.span(_ startsWith marker) val entrances = (head :: rows.toList) map { case Row(_, _, _, _, entrance) =&gt; entrance } val station = head match { case Row(division, line, station, routes, _) =&gt; Station( division, line, station, routes.toList.filter(_ != ""), entrances) } processByChunk(rest, acc += station) } } val file = new java.io.File("StationEntrances.csv") val reader = com.github.tototoshi.csv.CSVReader.open(file) val stations = processByChunk(reader.iterator.drop(1), ListBuffer()) reader.close stations } </code></pre> <p>I have created a dedicated extractor to get the routes/entrances from a given line. I think it makes the code more readable, but also if you are dealing with list, calling <code>fields(0)</code> to <code>fields(25)</code> is not optimal since each call has to traverse the list. The extractor avoids this. For most Java csv parsers, you usually get <code>Array[String]</code>, so that's usually not an issue. Finally, the csv parsing usually doesn't return null strings, so you may want to use <code>if (adaNotes == "") None else Some(adaNotes)</code> instead of <code>Option(adaNotes)</code>.</p> <pre><code>object Row { def unapply(s: Seq[String]) = s match { case List(division, line, station, rest @ _*) =&gt; val (routes, List(ada, adaNotes, freeCrossover, entranceType, entry, exitOnly, entranceStaffing, northSouthStreet, eastWestStreet, corner, latitude, longitude)) = rest splitAt 11 // 11 routes Some(( division, line, station, routes, Entrance( ada.toBoolean, Option(adaNotes), freeCrossover.toBoolean, entranceType, entry == "YES", exitOnly == "YES", entranceStaffing, northSouthStreet, eastWestStreet, corner, latitude.toInt, longitude.toInt))) case _ =&gt; None } } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload