jen
jen

Reputation: 357

Devide a range into x number of ranges

I have been breaking my head over this

I want to create a list of intervals (as Tuple2 instances) of a range between min and max divided in numberOfIntervals.

This particular project is in java (no scala allowed), so i am using vavr, but any scala solution i could probably translate to vavr

This is my solution:

final int numberOfIntervals = 7;

final int min = 1;
final int max = 100;

final int targetSize = (max - min) / numberOfIntervals + 1;
final List<Tuple2<Integer, Integer>> l = Iterator.rangeClosed(min, max)
        .grouped(targetSize)
        .map(l -> Tuple.of(l.head(), l.last())).toList();

This works:

(1, 15)
(16, 30)
(31, 45)
(46, 60)
(61, 75)
(76, 90)
(91, 100)

But this is created long intermediary lists. I have also been playing with something like this:

final int numberOfIntervals = 7;

final int min = 1;
final int max = 100;

final int targetSize = (max - min) / numberOfIntervals + 1;
final List<Tuple2<Integer, Integer>> l = Iterator
        .rangeClosedBy(min, max + targetSize, targetSize).sliding(2)
        .map(s -> of(s.get(0), s.get(1) - 1))
        .toList();

But with this the last range is larger than the max value:

(1, 15)
(16, 30)
(31, 45)
(46, 60)
(61, 75)
(76, 90)
(91, 105)

Upvotes: 2

Views: 1313

Answers (2)

jen
jen

Reputation: 357

Based on the suggestions of Piotr Wilkin i came up with the following

final int numberOfIntervals = 7;

final int min = 1;
final int max = 100;

final int targetSize = (int) Math.ceil((max - min) / numberOfIntervals) ;
final List<Tuple2<Integer, Integer>> l = Iterator
        .rangeBy(min, max + targetSize, targetSize).sliding(2)
        .map(s -> of(s.get(0), s.get(1)-1))
        .map(t->t.map2(i->Math.min(i,max)))
        .toList();

Upvotes: 0

Piotr Wilkin
Piotr Wilkin

Reputation: 3501

Your second code is better, but you won't get far with any code that's trying to compute regular intervals simply because the last interval is an exception - however you do it, you'll have to somehow include a condition that cuts its size.

I'd suggest using rangeBy instead of rangeClosed, that should get you a proper collection of the starting elements. You already have the interval size, although instead of hardcoding +1 (which will yield an incorrect result if your number of intervals divides the range size without a remainder) you might want to use Math.ceil(). Afterwards, you just want to map the starting numbers with map(x -> Tuple.of(x, Math.min(x + targetSize - 1, max))).

Upvotes: 1

Related Questions