monamona
monamona

Reputation: 1246

Java 8 Streams - filter by a property of an object

I've got an Object called Price, that describes the selling and buying behaviour of an item. Next to some other properties it looks mainly like this:

public class Price {
    private PriceType type;
    private int amount;
    private ItemData itemData;
    
    //...
}

with respective getters and setters. amount is the amount of this item that shall be sold/bought, and ItemData describes the specifications of the item. PriceType is an Enum, that's either PriceType.SELLING or PriceType.BUYING.

I now have a method, which job it is, to find the best matching Price in a list. All my Prices are stored in a list simply called pricesList. Until now, my method just went through the list, and returned the first Price that matched the PriceType and the ItemData:

public static Price getPriceByBiggestBaseAmountMatchingGivenAmount(
                        ItemData dataOfCollected, PriceType priceType, int amount) {
    return pricesList
        .stream()
        .filter(p -> 
            p.getItemData().equals(dataOfCollected) &&
            p.getType().equals(priceType))
        .findFirst().orElse(null);
}

However this completely ignores the fact that there is a minimal amount that must be respected. So, what I need is that it does not just find me the first Price that somehow matches the ItemData and the PriceType, but it should also take account the minimal amount. It should ignore every Price that has an amount smaller than the given amount, and of all the remaining ones, it should return the one with the biggest price.getAmount(). This might be a bit hard to understand so here's an example:

Say I have three Price-Objects of the same PriceType and ItemData, so they all describe, lets say a PriceType.BUYING price - ergo the price my program will pay for a given amount of this item.

price1.getAmount() == 1 //So this is describing the price for a single item.
price2.getAmount() == 6 //So this is describing the price for half a dozen of the item.
price3.getAmount() == 64 //Describing the price for an entire stack of the item.

If I do getPriceByBiggestBaseAmountMatchingGivenAmount(data, type, x) for some xes this shall be returned:

x: 1 => price1
x: 3 => price1
x: 7 => price2
x: 63 => price2
x: 64 => price3
x: 120 => price3
x: -1 => null

I have no idea how to achieve that with a stream, of course I could do it with a for loop, but that's something I'd only do as a last resort...

Upvotes: 1

Views: 2560

Answers (1)

Rahel Aumann
Rahel Aumann

Reputation: 46

Try it this way: First filtering out all prices that are smaller than the desired amount and then taking the biggest value out of the list with max().

public static Price getPriceByBiggestBaseAmountMatchingGivenAmount(
                    ItemData dataOfCollected, PriceType priceType, int amount) {
return pricesList
    .stream()
    .filter(p -> 
        p.getItemData().equals(dataOfCollected) &&
        p.getType().equals(priceType) &&
        p.getAmount() <= amount)  // remove bigger amounts
    .max(Comparator.comparing(Price::getAmount)) // take the biggest
    .orElse(null);
}

Upvotes: 3

Related Questions