将范围划分为 x 个范围

Devide a range into x number of ranges

我一直为此伤脑筋

我想创建 minmax 之间范围的间隔列表(作为 Tuple2 实例),分为 numberOfIntervals

这个特定的项目在 java 中(不允许使用 scala),所以我使用的是 vavr,但是任何 scala 解决方案我都可以转换为 vavr

这是我的解决方案:

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();

这个有效:

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

但这是创建长中间列表。我也一直在玩这样的东西:

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();

但是最后一个范围大于最大值:

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

你的第二个代码更好,但是你不会因为最后一个间隔是一个例外而尝试计算规则间隔的任何代码 - 无论你这样做,你都必须以某种方式包含一个条件减少它的大小。

我建议使用 rangeBy 而不是 rangeClosed,这应该可以让您正确收集起始元素。您已经有了间隔大小,尽管您可能想要使用 Math.ceil() 而不是硬编码(如果您的间隔数除以范围大小而没有余数,这将产生不正确的结果)。之后,您只想将起始数字映射为 map(x -> Tuple.of(x, Math.min(x + targetSize - 1, max))).

根据 Piotr Wilkin 的建议,我提出了以下建议

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();