2

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)
jen
  • 357
  • 2
  • 10
  • Since 100 values cannot be split into 7 equally sized groups, what result do you want? `100 / 7 = 14.285714`, so 6 groups of 15 and a final group of 10? 2 groups of 15 and 5 groups of 14? If so, then `15 15 14 14 14 14 14` or `14 14 14 14 14 15 15` or `14 14 14 15 14 14 15` or something else? – Andreas Nov 20 '17 at 10:36
  • @Andreas added the results, the last range would be smaller, so in this case `(91, 100)` – jen Nov 20 '17 at 10:38

2 Answers2

1

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))).

Piotr Wilkin
  • 3,446
  • 10
  • 18
0

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();
jen
  • 357
  • 2
  • 10