You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何配置CSV组件以映射字符串列表(含Eurovision数据示例)

解决Tototoshi CSV库实现国家到年份列表的映射问题

首先,你当前的代码有两个核心问题需要调整:一是CSVFormat的配置不完整,二是Map[String, String]只能存储单个年份,无法处理同一国家多次获奖的情况(比如瑞典在2012和2015年都获胜)。下面是完整的解决方案:

1. 补全CSVFormat配置

你的CSV文件没有使用引号包裹字段,所以需要把quoteChar设置为None(表示不使用引号),同时补全其他必要的格式参数:

implicit object CodesFormat extends CSVFormat {
  val delimiter: Char = ','
  val quoteChar: Option[Char] = None // 你的CSV无引号字段,设为None适配
  val escapeChar: Option[Char] = Some('\\') // 默认转义符,可按需调整
  val lineTerminator: String = "\n"
  val header: Boolean = true // 标记CSV第一行为表头
}

2. 修改映射类型与解析逻辑

countrEurovisionYearMap的类型从Map[String, String]改为Map[String, List[Int]](年份用整数更贴合业务逻辑),然后通过分组聚合的方式收集每个国家对应的所有年份:

import java.io.File
import com.github.tototoshi.csv._

object CountryEurovision {
  def countryEurovisionYearFile: File = new File("conf/countryEurovision.csv")
  
  // 调整映射类型为「国家 -> 获奖年份列表」
  lazy val countryEurovisionYearMap: Map[String, List[Int]] = getConvertData

  private def getConvertData: Map[String, List[Int]] = {
    implicit object CodesFormat extends CSVFormat {
      val delimiter: Char = ','
      val quoteChar: Option[Char] = None
      val escapeChar: Option[Char] = Some('\\')
      val lineTerminator: String = "\n"
      val header: Boolean = true
    }

    // 读取CSV并处理数据
    CSVReader.open(countryEurovisionYearFile).withFilter(_.nonEmpty) { reader =>
      reader.all().tail // 跳过表头行
        .map { case List(country, yearStr) => (country, yearStr.toInt) } // 年份转整数
        .groupBy(_._1) // 按国家分组
        .mapValues(_.map(_._2).sorted) // 提取年份列表并排序(可选)
    }
  }
}

关键改动说明

  • 格式适配quoteChar = None匹配你无引号的CSV格式,header = true让阅读器自动识别表头行。
  • 映射升级:用Map[String, List[Int]]替代单值映射,完美支持一个国家对应多个获奖年份的场景。
  • 数据聚合:通过groupBy按国家分组,再提取每个分组的年份列表,还可以按需对年份排序优化展示。
  • 类型优化:把年份字符串转为整数,避免后续业务逻辑中出现字符串转数字的重复操作。

如果需要处理文件不存在或格式错误的情况,可以在代码中加入try-catch捕获异常,增强鲁棒性。

内容的提问来源于stack exchange,提问作者MNY

火山引擎 最新活动