英文:
Optaplanner at least one occurency constraint
问题
I understand that you want a translation of the provided code without additional information. Here's the translated code:
我正在尝试实现一个约束,以便如果一个具有特定名称的元素没有至少分配一次,则会对解决方案进行惩罚。
我尝试使用 `GroupBy()` 但它不起作用:
```java
Constraint atLeastOne(ConstraintFactory cf) {
return cf
.forEach(Element.class)
.groupBy(Element::getName, ConstraintCollectors.countDistinct())
.filter((elementName, count) -> elementName == "foo" && count < 1)
.penalize(HardSoftScore.ONE_HARD)
.asConstraint("至少出现一次");
}
我的想法是,如果没有名称为 "foo" 的元素存在,过滤器将不返回任何内容,因此不会强制执行约束。
我还尝试使用 ifNotExists()
:
Constraint atLeastOne(ConstraintFactory cf) {
return cf
.forEach(Element.class)
.ifNotExists(Element.class, Joiners.filtering((a, b) -> a.getName() == "foo" && b.getName() == "foo"))
.penalize(HardSoftScore.ONE_HARD)
.asConstraint("至少出现一次");
}
问题是使用 ifNotExists()
也会对所有具有 a.getName() != "foo"
的元素进行惩罚。
有没有办法使它工作?
<details>
<summary>英文:</summary>
I'm trying to implement a constraint so that if an element with a specific name is not assigned at least one time, the solution is penalized.
I tried using `GroupBy()` but it does not work:
```java
Constraint atLeastOne(ConstraintFactory cf) {
return cf
.forEach(Element.class)
.groupBy(Element::getName, ConstraintCollectors.countDistinct())
.filter((elementName, count) -> elementName == "foo" && count < 1)
.penalize(HardSoftScore.ONE_HARD)
.asConstraint("At least one occurency");
}
My idea is that if no element with name "foo" is present the filter does not return anything and as a consequnce the costraint is not enforced.
I also tried using ifNotExists()
:
Constraint atLeastOne(ConstraintFactory cf) {
return cf
.forEach(Element.class)
.ifNotExists(Element.class, Joiners.filtering((a, b) -> a.getName() == "foo" && b.getName() == "foo"))
.penalize(HardSoftScore.ONE_HARD)
.asConstraint("At least one occurency");
}
The problem is that using ifNotExists()
also penalizes all the elements with a.getName() != "foo"
Any idea to make it work?
答案1
得分: 0
在约束流中,groupby()
只有在至少有一个输入元组时才会产生结果。这意味着"至少有 X 个" 约束必须分别实现为两个独立的约束:
- 一个约束用于惩罚没有元素满足约束的情况
- 一个约束用于惩罚一些(但不足够多)元素满足约束的情况(如果最小值是2或更多,则不需要此约束)
由于您正在使用分组键,您需要一种方法来访问"没有元素满足约束"情况下的所有可能键。在您的 @PlanningSolution
上创建一个包含所有可能名称的 ElementName
集合,并将其作为 @ProblemFactCollectionProperty
。然后,约束会如下所示:
Constraint atLeastOne(ConstraintFactory cf) {
return cf
.forEach(ElementName.class)
.filter(elementName -> elementName.getName().equals("foo"))
.ifNotExists(Element.class, Joiners.equal(ElementName::getName, Element::getName))
.penalize(HardSoftScore.ONE_HARD)
.asConstraint("至少有一个出现");
}
请注意,这是原文的翻译,没有包括代码部分。
英文:
In constraint streams, a groupby()
only produce a result if it has at least one input tuple. This means "have at least X" constraints must be implemented as two separate constraints:
- One constraint to penalize the case when no elements satisfy the constraint
- One constraint to penalize the case when some (but not enough) elements satisfy the constraint (this is not needed since minimum is 1, but would be needed if minimum was 2 or more)
Since you are using a grouping key, you need a way to access all possible keys for the "no elements satisfy the constraint" case. Create an ElementName
collection with all possible name and put it as a @ProblemFactCollectionProperty
on your @PlanningSolution
. Then the constraint would look like this:
Constraint atLeastOne(ConstraintFactory cf) {
return cf
.forEach(ElementName.class)
.filter(elementName -> elementName.getName().equals("foo"))
.ifNotExists(Element.class, Joiners.equal(ElementName::getName, Element::getName))
.penalize(HardSoftScore.ONE_HARD)
.asConstraint("At least one occurency");
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论