如何从集合中访问“已过滤”的项目?

时间:2017-07-25 18:36:20

标签: scala

我有一个字符串val trackingHeader = "k1=v1, k2=v2, k3=v3, k4=v4",我想解析它并将其转换为Map(k1 -> v1, k2 -> v2, k3 -> v3, k4 -> v4)。以下是我用来执行此操作的代码:

val trackingHeadersMap = trackingHeader
  .replaceAll("\\s", "")
  .split(",")
  .map(_ split "=")
  .map { case Array(k, v) => (k, v) }
  .toMap

我能够得到我想要的输出。但是,我还需要处理像val trackingHeader = "k1=v1, k2=v2, k3=v3, k4="这样格式错误的输入案例。请注意,密钥k4没有值。我的上述代码将开始使用scala.MatchError: [Ljava.lang.String;@622a1e0c (of class [Ljava.lang.String;),因此我将其更改为:

val trackingHeadersMap = trackingHeader
  .replaceAll("\\s", "")
  .split(",")
  .map(_ split "=")
  .collect { case Array(k, v) => (k, v) }
  .toMap

很好,我现在也使用collect来处理格式不正确的案例,但我想知道这个问题是什么密钥并将其记录下来(在此示例中为k4)。我尝试了下面的内容,并且能够得到理想的结果,但我不确定它是否是正确的方法:

val badKeys = trackingHeader
    .replaceAll("\\s", "")
    .split(",")
    .map(_ split "=")
    .filterNot(_.length == 2)

现在我可以遍历badKeys并打印出来。有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

您可以将结果设为可选,并使用flatMap代替map

 .flatMap {
    case Array(k, v) => Some(k -> v)
    case Array(k) => println(s"Bad entry: $k"); None
  }

答案 1 :(得分:0)

一种解决方案是添加map步骤,在调用collect之前打印与单元素数组匹配的元素的错误键:

val trackingHeadersMap = trackingHeader
  .replaceAll("\\s", "")
  .split(",")
  .map(_ split "=")
  .map {
    case v @ Array(k) => println(s"bad key: $k"); v
    case v => v
  }.collect {
    case Array(k, v) => (k, v)
  }
  .toMap

更好的解决方案(将副作用与转换分开)将是使用partition将其分成两个集合(“好”和“坏”),并分别处理每个集合:

val (good, bad) = trackingHeader
  .replaceAll("\\s", "")
  .split(",")
  .map(_ split "=")
  .partition(_.length == 2)

val trackingHeadersMap = good.map { case Array(k, v) => (k, v) }.toMap

bad.map(_(0)).foreach(k => println(s"bad key: $k"))