OptaPlanner约束中数组元素级求和及阈值校验问题求助
核心问题:对象列表的整数序列元素级求和
要实现多个同长度整数序列的元素级求和,Java流可以通过reduce操作完成。注意:Java泛型不支持基本类型,原示例中的ArrayList<int>是非法写法,实际应使用ArrayList<Integer>或者int[]数组。
针对List<Integer>的实现
// 定义对象类 class MyObject { private List<Integer> arrayOfInts; public List<Integer> getArrayOfInts() { return arrayOfInts; } public void setArrayOfInts(List<Integer> arrayOfInts) { this.arrayOfInts = arrayOfInts; } } // 求和逻辑 List<MyObject> listOfObjects = Arrays.asList( new MyObject() {{ setArrayOfInts(Arrays.asList(1,1,1)); }}, new MyObject() {{ setArrayOfInts(Arrays.asList(2,2,2)); }} ); List<Integer> result = listOfObjects.stream() .map(MyObject::getArrayOfInts) .reduce((list1, list2) -> { // 实际场景建议添加长度一致性校验 return IntStream.range(0, list1.size()) .map(i -> list1.get(i) + list2.get(i)) .boxed() .collect(Collectors.toList()); }) .orElse(Collections.emptyList()); // 空列表时返回空集合 // 输出结果:[3, 3, 3] System.out.println(result);
针对int[]数组的实现(性能更优)
如果时间序列用int[]存储,效率会比List<Integer>更高:
// 定义对象类 class MyObject { private int[] arrayOfInts; public int[] getArrayOfInts() { return arrayOfInts; } public void setArrayOfInts(int[] arrayOfInts) { this.arrayOfInts = arrayOfInts; } } // 求和逻辑 List<MyObject> listOfObjects = Arrays.asList( new MyObject() {{ setArrayOfInts(new int[]{1,1,1}); }}, new MyObject() {{ setArrayOfInts(new int[]{2,2,2}); }} ); int[] result = listOfObjects.stream() .map(MyObject::getArrayOfInts) .reduce(new int[0], (arr1, arr2) -> { int[] sumArr = new int[arr1.length]; for (int i = 0; i < arr1.length; i++) { sumArr[i] = arr1[i] + arr2[i]; } return sumArr; }); // 输出结果:[3, 3, 3] System.out.println(Arrays.toString(result));
OptaPlanner约束实现
回到你的OptaPlanner场景,要统计所有Operation的resourceUsage元素求和后超过阈值X的数量并惩罚,提供两种实现方案:
方案一:全数组汇总后校验
public Constraint resourceOveroccupation(ConstraintFactory constraintFactory) { int thresholdX = 5; // 替换为你的阈值 return constraintFactory.forEach(Operation.class) .map(Operation::getResourceUsage) // 假设返回int[]类型 .reduce((arr1, arr2) -> { int[] sumArr = new int[arr1.length]; for (int i = 0; i < arr1.length; i++) { sumArr[i] = arr1[i] + arr2[i]; } return sumArr; }) .filter(sumArr -> IntStream.of(sumArr).anyMatch(val -> val > thresholdX)) .penalize("Resource Overoccupation", HardMediumSoftScore.ONE_MEDIUM, sumArr -> (int) IntStream.of(sumArr).filter(val -> val > thresholdX).count()); }
方案二:分时间点统计(推荐)
如果时间序列长度固定,按单个时间点单独统计更适合OptaPlanner的增量计算逻辑(当Operation变动时,仅需更新对应时间点的统计值):
public Constraint resourceOveroccupation(ConstraintFactory constraintFactory) { int thresholdX = 5; int timeSeriesLength = 3; // 替换为你的时间序列固定长度 return constraintFactory.forEach(Operation.class) .flatMap(operation -> IntStream.range(0, timeSeriesLength) .mapToObj(timeIndex -> new AbstractMap.SimpleEntry<>(timeIndex, operation.getResourceUsage()[timeIndex]))) .groupBy(Map.Entry::getKey, sum(Map.Entry::getValue)) .filter((timeIndex, totalUsage) -> totalUsage > thresholdX) .penalize("Resource Overoccupation per Time Slot", HardMediumSoftScore.ONE_MEDIUM, (timeIndex, totalUsage) -> 1); // 每个超阈值的时间点惩罚1次 }
内容的提问来源于stack exchange,提问作者Rayamon
相关产品推荐
相关产品推荐

