如何在Scala中提取Array [String]的元素?

时间:2017-07-07 13:04:30

标签: arrays scala

假设我们有一个数组:

val arr = Array("Id:1; Apple; Red; 2; Out",
                "Id:2; Banana; Yellow; 5",
                "Id:3; Peach; Red; 3",
                "Id:4; Grape; Green; 5; Out")

我想在数组的每个元素上应用一个函数,它提取水果类型和数字并返回一个Map。这种情况下的输出是:

(Apple, 2)
(Banana, 5)
(Peach, 3) 
(Grape, 5)

我试过了:

val pairMap = arr.foreach(r => r.split(";")(1) zip r.split(";")(3))

但我总是获得Unit

2 个答案:

答案 0 :(得分:6)

您的代码实际上有两个错误。

首先正如你所指出的那样,你正在使用foreach(返回Unit)而不是map(返回Object)。

其次,您在zip函数中使用foreach,它结合了两个集合,如下所示:

val arr1 = Seq("Apple", "Peach", "Banana")
val arr2 = Seq("Red", "Red", "Yellow")

val arr3 = arr1 zip arr2 // = Seq(("Apple", "Red"), ("Peach", "Red"), ("Banana", "Yellow"))

您的代码应如下所示:

val arr = Array("Id:1; Apple; Red; 2; Out",
  "Id:2; Banana; Yellow; 5",
  "Id:3; Peach; Red; 3",
  "Id:4; Grape; Green; 5; Out")

arr.map(r => (r.split(";")(1), r.split(";")(3)))

或者通过仅拆分一次来提高效率:

arr.map { r =>
  val t = r.split(";")
  (t(1), t(2))
}

你可能不想要白色空间,所以:

arr.map { r =>
  val t = r.split(";")
  (t(1).trim(), t(2).trim())
}

只是添加这个因为我认为正则表达式也是字符串处理的一个很好的选择,并且与scala的模式匹配一​​起整洁的功能:

val regEx = "[^;]+; ([^;]+); [^;]+; ([^;]+).*".r

arr collect {
  case regEx(fruit, number) => (fruit, number)
}

也会导致所需的输出,但对于这个简单的用例可能有点过分。

答案 1 :(得分:1)

关闭,但您应该使用map代替foreach

这些高阶函数都接受一个函数并将其应用于集合的每个元素。

两者之间的区别可以在(简化的,非实际的)签名中看出:

trait Collection[A] {

  def map[B](f: A => B): Collection[B]

  def foreach(f: A => Unit): Unit

}

区别在于foreach用于进行某种操作或副作用发生(例如打印),而map ping产生的元素是那些元素的那些应用函数的起始集合:

List(1, 2, 3, 4).map(_ * 2).forech(print) // prints 2468

此外,必须稍微编辑该功能才能按预期工作:

arr.map {
  row =>
    val split = row.split(";") // split only once
    (split(1).trim, split(3).trim) // no zipping necessary
}

zip没有必要,因为您已经在处理每个项目,一次一个,而zip允许您压缩两个集合。

Seq(1, 2, 3) zip Seq('a', 'b', 'c') == Seq((1, 'a'), (2, 'b'), (3, 'c')) // true