2

Given this function, which I can't modify:

def numbers(c: Char): Iterator[Int] = 
  if(Character.isDigit(c)) Iterator(Integer.parseInt(c.toString)) 
  else Iterator.empty
// numbers: (c: Char)Iterator[Int]

And this input data:

val data = List('a','b','c','1','d','&','*','x','9')
// data: List[Char] = List(a, b, c, 1, d, &, *, x, 9)

How can I make this function lazy, such that data is only processed to the first occurrence of a number character?

def firstNumber(data: List[Char]) :Int = data.flatMap(numbers).take(1)
noahlz
  • 10,202
  • 7
  • 56
  • 75

4 Answers4

6
data.iterator.flatMap(numbers).take(1).toList

Don't use streams; you don't need the old data stored. Don't use views; they aren't being carefully maintained and are overkill anyway.

If you want an Int, you need some default behavior. Depending on what that is, you might choose

data.iterator.flatMap(numbers).take(1).headOption.getOrElse(0)

or something like

{
  val ns = data.iterator.flatMap(numbers)
  if (ns.hasNext) ns.next
  else throw new NoSuchElementException("Number missing")
}
Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
2

Just calling .toStream on your data should do it:

firstNumber(data.toStream)
Shadowlands
  • 14,994
  • 4
  • 45
  • 43
2

One possibility would be to use Scala's collection views: http://www.scala-lang.org/docu/files/collections-api/collections_42.html

Calling .view on a collection allows you to call functions like map, flatMap etc on the collection without generating intermediate results.

So in your case you could write:

data.view.flatMap(numbers).take(1).force

which would give a List[Int] with at most one element and only process data to the first number.

kong
  • 1,961
  • 16
  • 16
-1

you could use Streams:

http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Stream

One way of stream creation:

1 #:: 2 #:: empty
Stefan Kunze
  • 741
  • 6
  • 15