0

Suppose we have an Array:

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")

I want to apply a function on each element of the array, which extracts the fruit type and the number and returns a Map. The output in this case would be:

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

I tried:

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

but I always obtain Unit

1
  • That's because foreach returns Unit. Use map instead. You might also want to parse the numbers into integers (right now you will get strings). Commented Jul 7, 2017 at 13:06

2 Answers 2

6

You actually have two errors in your code.

First as pointed out already you are using foreach (which returns Unit) instead of map (which returns an Object).

Second, you are using zip in your foreach function, which combines two collections pair wise, like this:

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

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

Your code should look like this:

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)))

Or to be a tiny bit more efficient, by splitting only once:

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

And you probably don't want the white spaces, so:

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

Just adding this because I think regex is also a good option for string processing and a neat feature together with scala's pattern match:

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

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

Also leads to the desired output, but might be a bit overkill for this simple use case.

Sign up to request clarification or add additional context in comments.

4 Comments

Yes, I was looking for this. Thank you!
This is a correct solution, in the sake of efficiency one further thing would be to not traverse the collection twice by using map two times.
For the regex solution, do you just have to add parentheses around the element which you want to extract?
Yes, exactly. It's called a capture group ( a general regex thing ). But you need to be careful in case you have an element that does not match, you might want to add a default case in the pattern matching. Otherwise you will get a scala.MatchError exception. I changed the code to use collect, which will just go over non matching elements and ignore them
1

Close, but you should have used map instead of foreach.

Both these higher-order functions take a function and apply that to each element of the collection.

The difference between the two can be seen in the (simplified, not actual) signature:

trait Collection[A] {

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

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

}

The difference is that foreach is used to make some sort of action or side effect happen (e.g. printing), while mapping yields a collection whose elements are those of the starting collection with the function applied:

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

Furthermore, the function has to be edited a little bit in order to work as intended:

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

zip is not necessary because you are already processing each item, one at a time, while zip allows you to zip together two collection.

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

1 Comment

If I use map, I receive: pairMap: Array[scala.collection.immutable.IndexedSeq[(Char, Char)]] = Array(Vector(( , ), (A,2)), Vector(( , ), (B,5)), Vector(( , ), (P,3)), Vector(( , ), (G,5)))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.