0

I have a list:

val list1 = List("male:Adam", "male:Peter", "female:Jane", "female:Sue", "female:Jo", "other:John")

I want to create two lists, one of female names and one of male names. i.e.:

List("Adam", "Peter")
List("Jane", "Sue", "Jo")

I've done this with

val result = list1.groupBy(_.startsWith("male"))

So that result has the two lists mapped against true and false but with each element being "male:Adam" etc. But then I'd have to cycle through each list removing the male: and female: strings. This smells of non-functional.

Can anyone show how the above problem would be solved in a functional way?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Adam Davies
  • 2,742
  • 4
  • 33
  • 52

3 Answers3

4
val map = list1.map(s => s.split(":") match { 
  case Array(sex, name) => (sex, name) 
})
.groupBy { case (sex, name) => sex }
.mapValues(_.map{ case (sex, name) => name })

val male = map("male")
// List(Adam, Peter)
val female = map("female")
// List(Jane, Sue, Jo)
Peter Neyens
  • 9,770
  • 27
  • 33
  • Nice use of pattern matching for safer array access, +1 – dcastro Jul 14 '15 at 10:08
  • Loving this one!! Can you recommend any books where such style can be learned? – Adam Davies Jul 14 '15 at 10:20
  • @AdamDavies Any book on Scala should be OK. You could also take a good look to all the functions the Scala Collections API provides ([`List`](http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.List), [`Map`](http://www.scala-lang.org/api/current/index.html#scala.collection.Map), ...) – Peter Neyens Jul 14 '15 at 10:26
  • I like this answer and the use of pattern matching. Not sure I understand it but that's the fun part....Well done! Thank you – Adam Davies Jul 14 '15 at 10:30
2
val groups = list.map(_.split(":")).groupBy(_(0)).mapValues(_.map(_(1)))

val males = groups("male")
val females = groups("female")
dcastro
  • 66,540
  • 21
  • 145
  • 155
0

Use map function like

result(true).map(_.split(":")(1))
alatom
  • 41
  • 1
  • 6
  • `result(false).map(_.split(":")(1))` returns `List(Jane, Sue, Jo, John)` John should not be in the list. It is because of these little quirks why I'm having the problem. I tried `list1.groupBy(_.startsWith("male") || _.startsWith("female"))` but the second use of `_` throws a missing parameter error, which is what mystified my in the first place (hence the title of this post) :) – Adam Davies Jul 14 '15 at 10:05
  • 2
    @AdamDavies: `_.foo` is just a shorthand for `s => s.foo`, but when you want to use the parameter multiple times, you can't use the shorthand notation. It needs to be `s => s.startsWith("male") || s.startsWith("female")` in your example. – Sven Koschnicke Jul 14 '15 at 10:13
  • There's no "second use of the _" in your question, so I changed the title. It seems your question isn't really about that, anyway – The Archetypal Paul Jul 15 '15 at 06:43