Returning and iterable collection using yield in scala
Asked Answered
K

3

5

I have a DateTime and TimeSpan class in Scala (assume that the < and + operators work as they should). I'm trying to define a 'range' function that takes a start/stop time and a timespan for stepping. In C# I would do this with a yield, and I think I should be able to do the same in Scala... except I'm getting a strange error.

On the 'yield t' line, I get "Illegal start of statement".

  def dateRange(from : DateTime, to : DateTime, step : TimeSpan) =
  {
      // not sure what the list'y way of doing this is
    var t = from

    while(t < to)
    {
      yield t; // error: illegal start of statement
      t = t + step
    }
  }

Looking at this code, I am curious about 2 things: 1) what did I do wrong? 2) the code as written is very imperative (uses a var t, etc). What's the more functional way to do this in Scala that is reasonably fast?

Thanks!

Keratose answered 28/10, 2011 at 12:49 Comment(2)
yield in Scala has nothing whatsoever to do with yield in C# (or Python). Furthermore, Scala has no equivalent to it -- look up the many questions about Scala, Python, yield and generators. And, of course, look up the questions about what yield actually does.Several
I did, and I was confused. Debilski's answer told me all I needed to know.Keratose
A
17
def dateRange(from : DateTime, to : DateTime, step : TimeSpan): Iterator[DateTime] =
  Iterator.iterate(from)(_ + step).takeWhile(_ <= to)
Aether answered 28/10, 2011 at 13:11 Comment(1)
If I could give you a +1000, I would. That's awesome.Keratose
D
3

Here's a version of @Debilski solution with joda time periods:

import org.joda.time.{DateTime, Period}

def dateRange(from: DateTime, to: DateTime, step: Period): Iterator[DateTime] =
  Iterator.iterate(from)(_.plus(step)).takeWhile(!_.isAfter(to))
Decagon answered 5/3, 2013 at 13:28 Comment(0)
B
0

In Scala, yield is a special statement for for-loops.

I don't know C#, but from what I understand, I think the easiest for you is to use collection.immutable.NumericRange.Exclusive[DateTime] or collection.immutable.NumericRange.Inclusive[DateTime], depending on whether your interval is exclusive or inclusive.

For that to work, you will need to create an instance of Integral[DateTime] which defines the arithmetics for type DateTime.

Bilinear answered 28/10, 2011 at 13:10 Comment(1)
Well, Integral is kind of stupid to implement for DateTime it seems. The other approach with Iterator.iterate is much better.Bilinear

© 2022 - 2024 — McMap. All rights reserved.