I'm not sure what to call the property that's 2 layers deep.
But let's say we have List<FruitColor>
where Fruit
and Color
are 2 entities. (These are all example entities) A fruit
can have different color
s, but color
s can also have different fruit
s.
public class FruitColor {
private String fruitColorId;
private Fruit fruit;
private Color color;
private int ripe; //1 to 3 where 1 unripe 2 normal 3 ripe
// more props, getters, etc.
}
public class Fruit {
private String fruitId;
private String fruitName;
// getters, etc.
}
public class Color {
private String colorId;
private String colorName;
// getters, etc.
}
I'm thinking it in the following steps:
- Filter all the duplicates by
fruitName
- Pick one of the two 'duplicates'. I say 'duplicates' because they only have the same
name
, but not the samecolor
. The rule to choose which one to keep is the season/time-transition indicatorsystemTransition
, which is described by thedouble
propertysystemTransition
that ranges from0
to a100
. - Remove the other 'duplicate'.
- If there is a duplicate, makes the fruit less ripe by
0.5
- Set the
factorialRipeness
, which isripe * systemTransition
orripe * (100 - systemTransition)
depending on how far we are in the season, halfway is the threshold. - Return suggested
FruitColors
with the rightColor
, sorted byFactorialRipeness
The thing is, this is probably do-able with a lot of for loops, but I'm just wondering if there are any ways that are more efficient.
I did find this source on how to filter by property, but this solution doesn't let me filter on the property of a property(=fruitName
).
Java 8 Distinct by property
I've made a code example (again different entities) that works. Are there any parts that could be made more efficient? By more efficient I mean, if the code could be shorter and/or faster. I'll definitely refactor the method into smaller parts later. Sorry for the confusing bits, this problem is really hard to explain without using the exact same entities.
//logic in the method
{
List<FruitColor> fruitColors = getAllFCs();
//Remove if FC is neither colors that were chosen
fruitColors.removeIf(fc -> fc.getColor().getColorId() != presentColor.getColor().getColorId()
&& fc.getColor().getColorId() != futureColor.getColor().getColorId());
List<FruitColor> suggestedFruits = new ArrayList<>();
//Systemtransition is the season/time from 0 to 100, where 100 the fruit should be completely ripe with the corresponding color.
//If the time is less than half, it should pick the present color, which is the less ripe color.
boolean getPresentColorFruit = systemTransition < 50;
// --->This whole for-if-if-else-elseif-if-else part I wanted to make more "efficient" <---
for (FruitColor fruitColor : fruitColors) {
//First check for duplicate FCs
List<FruitColor> sameNameFruits = fruitColors.stream()
.filter(fc -> fc.getFruit().getName().equals(itemColor.getFruit().getName()))
.collect(Collectors.toList());
//If there is only one of the fruit, check if it's added already. If not, than add with proper ripeness
//FactorialRipeness is the "true" ripeness.
if (sameNameFruits.size() == 1 && !suggestedFruits.stream().anyMatch(fc -> fc.getFruit().getName().equals(sameNameFruits.get(0).getFruit().getName()))) {
FruitColor onlyOne = sameNameFruits.get(0);
if (onlyOne.getColor().getColorId() == presentColor.getColor().getColorId()) {
onlyOne.setFactorialRipeness(onlyOne.getRipeness() * systemTransition);
} else {
onlyOne.setFactorialRipeness(onlyOne.getRipeness() * (100 - systemTransition));
}
suggestedFruits.add(onlyOne);
// If there are multiple FCs, than the ripeness has to go down. Which prioritizes duplicate FCs more. (this part isn't logical with these entities, sorry)
} else if(!suggestedFruits.stream().anyMatch(fc -> fc.getFruit().getName().equals(sameNameFruits.get(0).getFruit().getName()))){
if (getPresentColorFruit) {
FruitColor fcWithPresentColor = sameNameFruits.stream()
.filter(fc -> fc.getColor().getColorId() == presentColor.getColor().getColorId()).findFirst()
.get();
fcWithPresentColor.setFactorialRipeness((fcWithPresentColor.getRipeness() - 0.5) * systemTransition);
suggestedFruits.add(fcWithPresentColor);
} else {
FruitColor fcWithFutureColor = sameNameFruits.stream()
.filter(fc -> fc.getColor().getColorId() == futureColor.getColor().getColorId()).findFirst()
.get();
//This part is also not logical, but if the presentColor is not chosen. Than we need to multiply by the opposite amount of the systemTransition
fcWithFutureColor.setFactorialRipeness((fcWithFutureColor.getRipeness() - 0.5) * (100 - systemTransition));
suggestedFruits.add(fcWithFutureColor);
}
}
}
//Sort by "true" ripeness value, from lowest to highest
Collections.sort(suggestedFruits, new FruitColorRipenessComparator());
return suggestedFruits;
}
/**
* @source https://stackoverflow.com/questions/2839137/how-to-use-comparator-in-java-to-sort
*/
public class FruitColorRipenessComparator implements Comparator<FruitColor> {
@Override
public int compare(FruitColor a, FruitColor b){
return a.getFactorialRipeness() < b.getFactorialRipeness() ? -1 : a.getFactorialRipeness() == b.getFactorialRipeness() ? 0 : 1;
}
}