Validating an object with a long list of predicates - java

I have an object, Bill, with a number of fields. In the method below, I get the bill with a function. I want to validate it with a list of Predicate<Bill>, which are paired with the appropriate error message to be applied if the predicate test fails. How can I accumulate the error messages given a list of tests, given that I can have more than eight conditions, and therefore won't be able to use Validation.combine?
default Validation<Seq<String>, Long> validate(
Long id,
Long, Bill> getBill,
List<Pair<Predicate<Bill>,String>> tests){
Bill bill = getBill.apply(id);
//I want to do the same thing
//but using the list I passed in,
//without the limitation of eight validations.
return Validation.combine(
validateBill(bill, Pair.of(hasDateInsurerReceivedBill, "Date Insurer Received Bill absent")),
validateBill(bill, Pair.of(EventValidation.hasEmployeeIdNumber, "Employee ID Number absent"))
).ap((x, y) -> id);
}
default Validation<String,Long> validateBill(
Bill bill, Pair<Predicate<Bill>, String> condition)
{
return condition.getFirst().test(bill) ?
Validation.valid(bill.getIntId())
: Validation.invalid(condition.getSecond());
}
I'm brand new to this library and I'm not terribly familiar with functional programming yet, so please use examples and the simplest terminology possible in any explanations.

I would do a nested combine and then flatten the results.
In our project we always have Seq<ValidationError> on the left side of a Validation, you don't have to but it is good to understand the code I'll show you.
With the first 8 Validations you return a new Validation in the .ap
When you return a Validation inside .ap you will end up with something like this:
Validation<Seq<ValidationError>, Validation<Seq<ValidationError>, String>> x = ...
The needs to be flattened with the following piece of code:
Validation
.combine(step1, step2, step3, step4, step5, step6, step7, step8)
.ap((a, b, c, d, e, f ,g, h) -> {
// do important stuff and
return Validation......
})
.mapError(Util::flattenErrors)
.fold(Validation::invalid, Function.identity());
The Util class:
public static Seq<ValidationError> flattenErrors(final Seq<Seq<ValidationError>> nested) {
return nested
.flatMap(Function.identity())
.distinct(); //optional duplicate filtering
}
With this new validation you can do the same trick again (you can add 7 new validations every time or create a few and do another combine, depends a bit on the number of validations you have).

Related

Optaplanner: manual grouping / group into multiple groups

I have the following dataset, and am trying to work out how to best write a specific constraint.
My PlanningEntity looks (roughly) as follows:
#PlanningEntity
public class Participation {
#PlanningId
private long id;
private Student student;
private Lesson lesson;
#PlanningVariable(valueRangeProviderRefs = "possibleEnrollments")
private Boolean enrolled;
}
whereby a Lesson has a public List<Subject> getSubjects() (note: a list of multiple subjects).
What I would like to do in my penalize method is look at all participations of a student/subject (single subject!) combination. In other words, if I have lesson A with subject 1, lesson B with subject 2 and lesson C with subjects 1 and 2, I would like to do a grouping in such a way that in my penalize function I get two (Student, List<Participation>) callbacks: one for subject 1 and one for subject 2, whereby the first lists contains lessons A and C, and the second list has lessons B and C. So, C is contained in two lists.
The following does not work:
constraintFactory
.forEach(Participation.class)
.groupBy(Participation::getStudent, Participation::getSubjects, toList())
since this groups on the entire List returned by Participation::getSubject and the set 1 and 2 attached to lesson C becomes a separate group.
I have currently 'solved' the problem as follows, with a custom UniConstraintCollection:
return constraintFactory
.forEach(Participation.class)
.groupBy(Participation::getStudent, new UniConstraintCollector<Participation, Map<Subject, List<Participation>>, Map<Subject, List<Participation>>>() {
#Override
public Supplier<Map<Subject, List<Participation>>> supplier() {
return HashMap::new;
}
#Override
public BiFunction<Map<Subject, List<Participation>>, Participation, Runnable> accumulator() {
return (map, participation) -> {
for(Subject s : participation.getSubjects()) {
if(!map.containsKey(s)) {
map.put(s, new ArrayList<>());
}
map.get(s).add(participation);
}
return () -> {
for(Map.Entry<Subject, List<Participation>> entry: map.entrySet()) {
entry.getValue().remove(participation);
}
};
};
}
#Override
public Function<Map<Subject, List<Participation>>, Map<Subject, List<Participation>>> finisher() {
return Function.identity();
}
}).penalize(("name", HardSoftScore.ONE_SOFT, (student, participationMap) -> {
...
});)
This works, in that I receive a map of Subject to Participations and allows me to calculate the penalty I want.
However, this means that I calculate one penalty value for all subject/list combinations 'together'. From a usability perspective, I would like to penalize each subject/list separately. Is there a way to do this? (Maybe by rewriting the UniConstraintCollector to provide multiple lists of Participations, instead of one single Map<Subject, List<Participation>>?)
P.S. Another approach I have tried to achieve the same goal is to work from the perspective of the Subject. So, making Subjects a ProblemFact on the PlanningSolution, and working with something like
return constraintFactory
.forEach(Subject.class)
.join(constraintFactory.forEach(Participation.class),
JoinerSupport.getJoinerService().newBiJoiner(List::of, JoinerType.INTERSECTING, Participation::getSubjects)
)
I assume this is the way I would need to go, using the JoinerType INTERSECTING, but this gives me an "Unsupported Joiner Type" exception in AbstractLeftHandSide.
What if you start from Subject?
constraintFactory
.forEach(Subject.class)
.join(Participation.class,
// Joiners.containedBy() would do this far more efficient
filtering((s, p) -> p.getSubjects().contains(s))
.groupBy((s, p) -> s, toList((s, p) -> p))
This could be an expensive constraint performance wise. Benchmark it.
This isn't really an answer, but it might solve your problem too. It's too long to add as a comment.
The Boolean planning variable is typically an anti-pattern.
If you improve your model, the constraint might become easier to implement.
Instead, you could model it like this:
#PlanningEntity
public class Participation {
#PlanningId long id;
Student student;
#PlanningVariable(...) Lesson lesson;
}
This simpler model (on the right) will solve far more efficiently. But in this case, how many Participation instances should you create?
If the numbers of lessons for each student is fixed, that's obvious: that number per student.
If the numbers of lessons for each student is a planning decision, use overconstrainted planning: #PlanningVariable(nullable=true,...) Lesson lesson and create one participation for the maximum number of lessons of each student. This will allow the solver to leave some participation instances unassigned.
See also the Domain Modeling Guide in the docs.

In Java, a "decorate and sort" concise implementation?

I'm learning Java for the first time (my prior experience is Python and Haskell). I have a situation that would, in Python, require a "decorate and sort" idiom. Such as the following (code not tested but this is roughly correct):
origList = <something>
decorated = sorted( [(evalFunc(item), item) for item in origList] )
finalList = [item for _, item in decorated]
By choosing a different evalFunc you can choose how this is sorted.
In Java, I'm writing a program that composes music by choosing from among a list of notes, evaluating the "fitness" of each note, and picking the best. I have a class representing musical notes:
class Note {
...
}
I have a class that represents the fitness of a note as two values, its goodness and badness (yes, these are separate concepts in my program). Note: in Python or Haskell, this would simply be a 2-tuple, but my understanding is that Java doesn't have tuples in the usual sense. I could make it a pair, but it gets unwieldy to declare variables all over the place like List<Pair<Type1,Pair<Type2,Type3>>>. (As an aside, I don't think Java has type aliases either, which would let me shorten the declarations.)
class Fitness {
double goodness;
double badness;
}
The function that evaluates the fitness needs access to several pieces of data other than the Note. We'll say it's part of a "Composition" class:
class Composition {
... data declared here ... ;
public Fitness evaluate(Note n) {
}
}
I'd like to be able to compare Fitness objects in numerical order. There are two ways to compare: either goodness or badness can be numerically compared, depending on the situation.
class CompareFitnessByGoodness implements Comparator<Fitness> {
}
class CompareFitnessByBadness implements Comparator<Fitness> {
}
I'd like to package the Note together with its fitness, so I can sort the combined list by fitness and later pull out the best Note.
class Together {
public Note;
public Fitness;
}
I'd like to sort a List<Together> by either the goodness, or by the badness. So I might need:
class CompareTogetherByGoodness implements Comparator<Together> {
...
}
class CompareTogetherByBadness implements Comparator<Together> {
...
}
Eventually I'll write something like
Note pickBest(List<Together> notes) {
// Pick a note that's not too bad, and pretty good at the same
// time.
// First sort in order of increasing badness, so I can choose
// the bottom half for the next stage (i.e. the half "least bad"
// notes).
Collections.sort(notes, new CompareTogetherByBadness());
List<Together> leastBadHalf = notes.subList(0, notes.size()/2);
// Now sort `leastBadHalf` and take the last note: the one with
// highest goodness.
Collections.sort(leastBadHalf, new CompareTogetherByGoodness());
return leastBadHalf.get(leastBadHalf.size()-1);
}
Whew! That is a LOT of code for something that would be a few lines in Haskell or Python. Is there a better way to do this?
EDIT:
Addressing some of the answers.
"You don't need to decorate." Well, my fitness computation is very expensive, so I want to compute it once for each note, and save the result for later access as well.
"Store goodness/badness in Note." The goodness or badness is not a property of the note alone; it's only meaningful in context and it can change. So this is a suggestion that I add mutable state which is only meaningful in some contexts, or plain wrong if there's a bug which accidentally mutates it. That's ugly, but maybe a necessary crutch for Java.
Going by what you already have
origList = <something>
decorated = sorted( [(evalFunc(item), item) for item in origList] )
finalList = [item for _, item in decorated]
This is the equivalent in modern Java:
Given your composition object:
Composition composer = ...;
And a list of notes:
List<Note> notes = ...;
Then you can do:
List<Together> notesAllTogetherNow = notes.stream()
.map(note -> new Together(note, composer.evaluate(note)))
.sorted(new CompareTogetherByGoodness())
.collect(Collectors.toList());
To get the best note, you can take a bit further:
Optional<Note> bestNote = notes.stream()
.map(note -> new Together(note, composer.evaluate(note)))
.sorted(new CompareTogetherByBadness())
.limit(notes.size() / 2) // Taking the top half
.sorted(new CompareTogetherByGoodness())
.findFirst() // Assuming the last comparator sorts in descending order
.map(Together::getNote);
You can use streams:
Function<Foo, Bar> func = ...
Comparator<Foo> comparator = ...
var list = ...
var sorted = list.stream()
.sorted(comparator)
.map(func)
.collect(Collectors.toList());
Java plainly includes a Collections.sort :: List -> Comparator -> List that does everything for you. It mutates the original list, though.
Unfortunately, Java's standard library does not include tuples and even a plain Pair; the Apache Commnons library does, though.
In short, you don't need the decorate / undecorate approach in Java.
class Fitness {
double goodness;
double badness;
}
class Together {
Note note;
Fitness fitness;
}
class Note{
}
List<Together> notes = ...
Collections.sort(notes, Comparator.comparingDouble(value -> value.fitness.badness));
List<Together> leastBadHalf = notes.subList(0, notes.size()/2);
return leastBadHalf.stream().max(Comparator.comparingDouble(value -> value.fitness.goodness));

How to collect results after filtering and mapping a parallelStream in Java8?

I want to extract a collection of objects from another collection. The objects to be filtered must be a specific type (or subtype) and must intersect with a given Shape. I want to do it with parallelStream
I have the following code:
public class ObjectDetector {
...
public ObjectDetector(final Collection<WorldObject> objects,
final BiFunction<Shape, Shape, Boolean> isIntersecting) {
...
}
public List<ISensor> getSonarObjects(final Shape triangle) {
return selectIntersecting(triangle, ISensor.class);
}
private <T> List<T> selectIntersecting(Shape triangle, Class<T> type) {
return objects.parallelStream()
.filter(o -> type.isInstance(o) && isIntersecting.apply(o.getShape(), triangle))
.map(o -> type.cast(o)).collect(Collectors.toList());
The problematic part is in the List<T> selectIntersecting(Shape triangle, Class<T> type) method, in which objects is a Collection and isIntersecting is a BiFunction<Shape,Shape,Boolean>.
When I'm using stream() instead of parallelStream() all my tests are green. So I may assume that the filtering and mapping logic works fine. However when I am trying to use the parallelStream() my tests are failing unpredictably. The only coherence that I was able to observe is that the size() of the returned List<T> is less than or equal to (but of course never greater) the size I expect.
A failing testcase for example:
int counter = 0;
public BiFunction<Shape, Shape, Boolean> every2 = (a, b) -> {
counter++;
return counter % 2 == 0 ? true : false;
};
#Test
public void getEvery2Sonar() {
assertEquals("base list size must be 8",8,list.size());
ObjectDetector detector = new ObjectDetector(list, every2);
List<ISensor> sonarable = detector.getSonarObjects(triangle);
assertEquals("number of sonar detectables should be 3", 3, sonarable.size());
}
And the test result is:
Failed tests: getEvery2Sonar(hu.oe.nik.szfmv.environment.ObjectDetectorTest): number of sonar detectables should be 3 expected:<3> but was:<2>
In my understanding - as it is written here - it is possible to collect a parallelStream into non-concurrent Collection.
I've also tried to find some clues on the Parallelism tutorial page, but I'm still clueless.
Could someone please provide me an explanation about what am I doing wrong?
Your predicate function has side effects - this is going to go badly with parallelStream because the evaluation order across the input stream is non-deterministic, plus you have no locking on your mutable state.
Indeed, the documentation for filter states* that the predicate must be stateless.
I'm not sure what behaviour you're trying to achieve here, so I'm not sure what an appropriate "fix" might be.
* No pun intended.

Fast ordered list matching algorithm in Java

I have a list of rules in the form
L1 -> (A, B, C)
L2 -> (D, E),
L3 -> (F, G, A),
L4 -> (C, A)
.....
This list contains ~30k such rules.
I have an input in the form (X, Y, Z)
This creates a method
List <Rule> matchRules(input)
Which belongs to a class RuleMatcher
I started with a very simple clear naive solution, in order to get the framework down, get something working.
public RuleMatcher(Collection<Rule> rules) {
this.rules = rules;
}
public Collection<Rule> matchRules(List<Token> input) {
List<Rule> matchingRules = new ArrayList<>();
for(Rule r: this.rules) {
if(r.matches(input)) {
matchingRules.add(r);
}
}
return matchingRules;
}
Where matches is a very simple function that checks if the lengths are the same, and then checks each token as a for loop.
This matchRules function is called in the magnitude of billions of times.
Obviously this is a very poor implementation. According to my profiler at least half of the execution time is is spent in this matches function.
I was thinking of two possible solutions:
A. Some sort of Trie data structure holding the chains of rules which could be matched.
B. some sort of hash function. Each symbol is given a unique identifier. Unfortunately, there are about 8 thousand unique symbols so this might be difficult.
C. Make a hashmap conditioning on the size of the right hand side, the number of tokens in the rule. Unfortunately, the majority of the rules are about the same size, so this may not even be worthwhile.
D. Some awesome solution one of you come up with.
I hope somebody can shed some light on this problem.
Edit: A token is just an object with a unique number. For example "NN" is a token. Each instance of "NN" is exactly the same.
Matches code:
public boolean rhsMatches(List<Token> tokens) {
if(tokens.size()!=rhsSize()) return false;
for(int i = 0;i<rhsSize();i++) {
if(!rightSide.get(i).equals(tokens.get(i)) {
return false;
}
}
return true;
}
Its not very pretty, but its simple.
Why not sort your rule list to begin with. Then you can binary search for the matching rule.
To me it looks like a perfect scenario for engaging some worker threads.
Tasks of matching seem independent of each other, divide the list of rules and delegate the matching to workers, if its possible in your situation.

Search Function in Java Data Structure

I have created a large amount of People beans and was wanting to store them in some kind of data structure where I would be able to search for particular types of People beans (e.g. People beans with a last name of "Sanchez") as fast as possible (I don't want to use a DB by the way). Is the only way to loop over my beans and test currBean.getLastName().equals("Sanchez") for each bean?
I would like to be able to do something like the following:
List<PeopleBean> myPeople = myBeansDataStructure.getAll(new PeopleBean("John", "Sanchez", 36),
new Comparator<PeopleBean>() {
#Override
public int compare(PeopleBean b1, PeopleBean b2) {
// search conditions
}
});
and have it return a collection of beans matching the search. My searches will always be of the same 'kind', i.e., I will be either searching for beans with a particular last name, first name, or age (or some permutation of the three) so could something using an overridden equals method in the bean be used?
I am surprised this isnt there in the library.. or is it?
Anyway, you can write your own
public interface Condition<T> {
public bool satisfies(T t);
}
And write a generic searcher, which goes through the entire and applies this function to each of them and returns you a new of only the ones that return true.
You can use Java 8 (This is under the assumption that myBeansDataStructure is a Collection of some sort.):
List<PeopleBean> myPeople = myBeansDataStructure.stream().filter(person -> person.getLastName().equals("Sanchez")).collect(Collectors.toList());
Or you could try something like this:
List<PeopleBean> myPeople = myBeansDataStructure.stream().map(PeopleBean::getLastName).filter(lastName -> lastName.equals("Sanchez")).collect(Collectors.toList());
You can try this
List<PeopleBean> list=new ArrayList<>();
for(PeopleBean i:list){
if(i.getName().equals("whatEverName")){
//do something
}
}

Categories