OptaPlanner, could PlanningVariable be set to null which is not in the range - optaplanner

optaplanner-bom 7.59.0.Final. In my PlanningEntity class Task there is a PlanningVariable and a CustomShadowVariable
#PlanningVariable(valueRangeProviderRefs = "indexRange")
private Index index;
#CustomShadowVariable(variableListenerClass = UpdatingVariableListener.class,
sources = { #PlanningVariableReference(variableName = "index") })
private Long d;
in the PlanningSolution class the range is referred:
#ProblemFactCollectionProperty
#ValueRangeProvider(id = "indexRange")
private List<Index> indexList;
the rule file is to minimize the sum of all "d"s:
rule
when
accumulate(
Task(index != null, $d: d);
$s: sum($d)
)
then
scoreHolder.addSoftConstraintMatch(kcontext, 1, (int)(-$s));
end
in the afterVariableChanged() of the UpdatingVariableListener, by calling scoreDirector.getWorkingSolution(), I can see in the variable "indexList" there are two elements (let's call them "1" and "2") and none of them is java "null". When I set breakpoint in the afterVariableChanged(), with the first hit the "index" is "2", the second time it's "1", the third time is java "null". And noticed that for the second time and third time, the solution object are the same object. Do not think "null" should be set as it's not in the range. Anything wrong was done?

Related

Kotlin string exists but can't use almost all string functionality

Summary: I have a string from which I can print and use substring, but can't use attributes such as length or functions such as .toInt() or .compareTo(), why would this be the case?
var s = "20"
val myToast = Toast.makeText(this, s, Toast.LENGTH_SHORT)
myToast.show()
//20
val myToast2 = Toast.makeText(this, s.length, Toast.LENGTH_SHORT)
myToast2.show()
//The app crashes with the error: android.content.res.Resources$NotFoundException: String resource ID #0x2
I can call substring on string s, but I can't call length, toInt(), compareTo(), etc.
The string clearly exists since I can print it and use substring but if that is true why does my app throw an error when I try to use other attributes and functions from it?
There are two overloads of Toast.makeText(). One accepts a String as the second argument, and displays that string. The other accepts an Int as the second argument, and displays whatever string resource has that integer id. (Normally you'd pass something like R.string.my_string here.)
When you call .length on your String, you'll get an Int back. And that means you wind up calling the second overload, which then looks for a string resource with the id 2. That doesn't exist, so you crash.
If you want to just display the number 2, then you need to make this a String again. You can use .toString() or "${s.length}", and so on.
Add .toString at the end of length,toInt(),compareTo(), etc. because s.length
return int :not String
Here is your modified answer
var s = "20"
val myToast = Toast.makeText(this, s, Toast.LENGTH_SHORT)
myToast.show()
//20
val myToast2 = Toast.makeText(this, s.length.toString(), Toast.LENGTH_SHORT)
myToast2.show()

Java8 Streams - Compare Two List's object values and add value to sub object of first list?

I have two classes:
public class ClassOne {
private String id;
private String name;
private String school;
private String score; //Default score is null
..getters and setters..
}
public class ClassTwo {
private String id;
private String marks;
..getters and setters..
}
And, I have two Lists of the above classes,
List<ClassOne> listOne;
List<ClassTwo> listTwo;
How can I compare two list and assign marks from listTwo to score of listOne based on the criteria if the IDs are equal. I know, we can use two for loops and do it. But I want to implement it using Java8 streams.
List<ClassOne> result = new ArrayList<>();
for(ClassOne one : listOne) {
for(ClassTwo two : listTwo) {
if(one.getId().equals(two.getId())) {
one.setScore(two.getmarks());
result.add(one);
}
}
}
return result;
How can I implement this using Java8 lambda and streams?
Let listOne.size() is N and listTwo.size() is M.
Then 2-for-loops solution has complexity of O(M*N).
We can reduce it to O(M+N) by indexing listTwo by ids.
Case 1 - assuming listTwo has no objects with the same id
// pair each id with its marks
Map<String, String> marksIndex = listTwo.stream().collect(Collectors.toMap(ObjectTwo::getId, ObjectTwo::getMarks));
// go through list of `ObjectOne`s and lookup marks in the index
listOne.forEach(o1 -> o1.setScore(marksIndex.get(o1.getId())));
Case 2 - assuming listTwo has objects with the same id
final Map<String, List<ObjectTwo>> marksIndex = listTwo.stream()
.collect(Collectors.groupingBy(ObjectTwo::getId, Collectors.toList()));
final List<ObjectOne> result = listOne.stream()
.flatMap(o1 -> marksIndex.get(o1.getId()).stream().map(o2 -> {
// make a copy of ObjectOne instance to avoid overwriting scores
ObjectOne copy = copy(o1);
copy.setScore(o2.getMarks());
return copy;
}))
.collect(Collectors.toList());
To implement copy method you either need to create a new object and copy fields one by one, but in such cases I prefer to follow the Builder pattern. It also results in more "functional" code.
Following code copies marks from ObjectTwo to score in ObjectOne, if both ids are equal, it doesn't have intermediate object List<ObjectOne> result
listOne.stream()
.forEach(one -> {listTwo.stream()
.filter(two -> {return two.getId().equals(one.getId());})
.limit(1)
.forEach(two -> {one.setScore(two.getMarks());});
});
This should work.
Map<String, String> collect = listTwo.stream().collect(Collectors.toMap(ObjectTwo::getId, ObjectTwo::getMarks));
listOne
.stream()
.filter(item -> collect.containsKey(item.getId()))
.forEach(item -> item.setScore(collect.get(item.getId())));

Hibernate search boolean filter

I have book entry:
#Entity
#Indexed
public class Book extends BaseEntity {
#Field
private String subtitle;
#DateBridge(resolution = Resolution.DAY)
private Date publicationDate;
#Field
private int score;
#IndexedEmbedded
#ManyToMany(fetch = FetchType.EAGER)
#Cascade(value = {CascadeType.ALL})
private List<Author> authors = new ArrayList<Author>();
#Field
#FieldBridge(impl = BooleanBridge.class)
private boolean prohibited;
And filter by boolean field "phohibited"
public class BFilter extends Filter {
#Override
public DocIdSet getDocIdSet(IndexReader indexReader) throws IOException {
OpenBitSet bitSet = new OpenBitSet(indexReader.maxDoc());
TermDocs termDocs = indexReader.termDocs(new Term("prohibited","false"));
while (termDocs.next()) {
bitSet.set(termDocs.doc());
}
return bitSet;
}
}
Search method
public List<T> findByQuery(Class c, String q) throws InterruptedException {
FullTextSession fullTextSession = Search.getFullTextSession(session);
fullTextSession.createIndexer().startAndWait();
QueryBuilder qb = fullTextSession.getSearchFactory().buildQueryBuilder().forEntity(c).get();
Query luceneQuery = qb
.keyword()
.fuzzy()
.onFields("title", "subtitle", "authors.name", "prohibited", "score")
.matching(q)
.createQuery();
FullTextQuery createFullTextQuery = fullTextSession.createFullTextQuery(luceneQuery, Book.class, BaseEntity.class);
createFullTextQuery.setFilter(new BFilter());
return createFullTextQuery.list();
}
if I apply that filter - search result is empty. Entries in the database 100% there. What am I doing wrong? If you replace the filter field to "score" that all works, and the result is not empty. Do not search it on a Boolean field
The basic approach looks ok. A couple of comments. You are calling the indexer for each findByQuery call. Not sure whether this is just some test code, but you should index before you search and only once or when things change (you can also use automatic index updates). It might also be that depending on your transaction setup, your search cannot see the indexed data. However, you seem to say that all works if you don't use a filter at all. In this case I would add some debug to the filter or debug it to see what's going on and if it gets called at all. Last but not least, you don't need to explicitly set explicitly #FieldBridge(impl = BooleanBridge.class).

Checking for a specific value in an ArrayList

I need to determine if a element in my ArrayList has a specific value. This is the current way I am trying.
public static boolean hasDwgNamedReference(Object valueDWG){
boolean b = false;
String dwgName = "dwg_";
if(valueDWG == null){
b = false;
}
else {
String checkNamedRef = Arrays.toString((Object[]) valueDWG).substring(1, 5);
System.out.println("checkNamedRef " + checkNamedRef + "\n");
if(checkNamedRef.equals(dwgName)){
b = true;
}
}
return b;
}// end hasDwgNamedReference
I am pretty sure that the issue is with the
String checkNamedRef = Arrays.toString((Object[]) valueDWG).substring(1, 5);
Do you think I need to increment the ArrayList and check each element?
Well, firstly, you do not need to include the first "if" statement. b is already false, so setting it to false again is unnecessary.
If you use the Arrays.toString() method on an object, you may get the identity of the object, or the address in memory that it holds. If you try to compare to checkNamedRef via an equals method, you may be comparing an address and a string, which would never give you the true you are looking for.

Strange "Expected invocation on the mock at least once, but was never performed" error when I am setting up the Mock

I'm getting this error from Moq via NUnit, and it doesn't make much in the way of sense to me.
"Expected invocation on the mock at least once, but was never performed: x => x.DeleteItem(.$VB$Local_item)"
"at Moq.Mock.ThrowVerifyException(MethodCall expected, IEnumerable1 setups, IEnumerable1 actualCalls, Expression expression, Times times, Int32 callCount)
at Moq.Mock.VerifyCalls(Interceptor targetInterceptor, MethodCall expected, Expression expression, Times times)
at Moq.Mock.Verify[T](Mock mock, Expression1 expression, Times times, String failMessage)
at Moq.Mock1.Verify(Expression`1 expression)
at PeekABookEditor.UnitTests.ItemBrowsing.Can_Delete_Item() in C:\Projects\MyProject\MyProject.UnitTests\Tests\ItemBrowsing.vb:line 167"
Very similar code works well in C#, so the error might be minor and syntactical on my part.
Here's my code:
<Test()> _
Public Sub Can_Delete_Item()
'Arrange: Given a repository containing some item...
Dim mockRepository = New Mock(Of IItemsRepository)()
Dim item As New Item With {.ItemID = "24", .Title = "i24"}
mockRepository.Setup(Function(x) x.Items).Returns(New Item() {item}.AsQueryable())
'Act ... when the user tries to delete that product
Dim controller = New ItemsController(mockRepository.Object)
Dim result = controller.Delete(24)
'Assert ... then it's deleted, and the user sees a confirmation
mockRepository.Verify(Sub(x) x.DeleteItem(item))
result.ShouldBeRedirectionTo(New With {Key .action = "List"})
Assert.AreEqual(DirectCast(controller.TempData("message"), String), "i24 was deleted")
End Sub
The guilty line appears to be "mockRepository.Verify(Sub(x) x.DeleteItem(item))"
Any thoughts on how to fix this?
Working C# code isn't the exact same, but here it is:
[Test]
public void Can_Delete_Product()
{
// Arrange: Given a repository containing some product...
var mockRepository = new Mock<IProductsRepository>();
var product = new Product { ProductID = 24, Name = "P24"};
mockRepository.Setup(x => x.Products).Returns(
new[] { product }.AsQueryable()
);
// Act: ... when the user tries to delete that product
var controller = new AdminController(mockRepository.Object);
var result = controller.Delete(24);
// Assert: ... then it's deleted, and the user sees a confirmation
mockRepository.Verify(x => x.DeleteProduct(product));
result.ShouldBeRedirectionTo(new { action = "Index" });
controller.TempData["message"].ShouldEqual("P24 was deleted");
}
In your VB test method, you create Item with a string ItemID = "24", but you call the controller.Delete method with an integer value of 24.
Check your controller code and see if the type discrepancy results in the item not being identified correctly, so either DeleteItem is not called at all, or is called with a different Item.