22

In Scala, I want to split a string at a specific character like so:

scala> val s = "abba.aadd" 
s: String = abba.aadd
scala> val (beforeDot,afterDot) = (s takeWhile (_!='.'), s dropWhile (_!='.'))
beforeDot: String = abba
afterDot: String = .aadd

This solution is slightly inefficient (maybe not asymptotically), but I have the feeling something like this might exist in the standard library already. Any ideas?

Machavity
  • 30,841
  • 27
  • 92
  • 100
Felix
  • 8,385
  • 10
  • 40
  • 59

2 Answers2

50

There is a span method:

scala> val (beforeDot, afterDot) = s.span{ _ != '.' }
beforeDot: String = abba
afterDot: String = .aadd

From the Scala documentation:

c span p is equivalent to (but possibly more efficient than) (c takeWhile p, c dropWhile p), provided the evaluation of the predicate p does not cause any side-effects.

Jens Hoffmann
  • 6,699
  • 2
  • 25
  • 31
senia
  • 37,745
  • 4
  • 88
  • 129
3

You can use splitAt for what you want:

val s = "abba.aadd"
val (before, after) = s.splitAt(s.indexOf('.'))

Output:

before: String = abba
after: String = .aadd
serejja
  • 22,901
  • 6
  • 64
  • 72
  • Traverses the sequence twice, though – The Archetypal Paul May 06 '14 at 09:43
  • Not necessarily. Depends on the Scala optimiser. – Rok Kralj Nov 01 '14 at 19:48
  • 2
    I think it is worthwhile to mention that accessing indices of sequences should probably be avoided if possible, the reason being that random access is prone to one-off errors and rarely lends itself to composition within functional programming (this is based on my experience). Where random access comes into play is often in performance optimizations where arrays are often the target datastructure. – Felix May 02 '16 at 07:13
  • 2
    `splitAt` is for `take` and `drop`, `span` is for `takeWhile` and `dropWhile`. – pihentagy May 04 '18 at 06:30