Search code examples
sortingjava-8sumjava-streamcumulative-sum

how to use Java 8 streamAPI in this situtation


public int getTotalPrice(ArrayList<Book> books) {
        int sum = books.stream()
                .mapToInt(Book::getPrice)
                .sum();
        if (books.size() >= 5 && sum >= this.minimumPrice) {
            int res =(int) books.stream()
                    .mapToInt(Book::getPrice)
                    .boxed()
                    .sorted(Collections.reverseOrder())
                    .limit(2)
                    .mapToDouble(price -> price * 0.5)
                    .sum();
            return books.stream()
                    .skip(2)
                    .mapToInt(Book::getPrice)
                    .sum()
                    + res;
        }
        return sum;
    }

I want to implement the "getTotalPrice" method.

The discount rules are as follows

If you have 5 or more books and the price of all of them added together is equal to or greater than "this.minimumPrice", then the two most expensive books in your cart will be half price.

I want to implement this with stremapi in java 8. How can I do that?

The above code was written by myself.

If you have a better way to do it, I'd love to hear about it.

I extracted the prices from the stream of books and sorted them in descending order.

I discounted the top two most expensive prices by 50% and substituted them into "res".

Then, to get the sum of the prices of the remaining books, I skipped two and took the sum.

Is sorting necessary here to get the prices of the remaining books?


Solution

  • It's perfectly okay to solve it the way you did. But still a suggestion for improvement would be not to make everything in one method but to outsource in several methods, so that one method does only one task. This makes your code more readable and maintainable. Especially when requirements change, like the discount rate or when additional discount campaigns should be added.

    For example, the calculation of the total sum and the calculation of discount could be moved to their own methods.

    public int getTotalPrice(List<Book> books) {
        int totalSum              = getTotalSum(books);
        boolean hasMinBookCount   = books.size() > 4;
        boolean overTotalMinPrice =  totalSum > this.minimumPrice;
    
        if (!hasMinBookCount || !overTotalMinPrice){
            return totalSum;
        }
        return (int) (totalSum - getDiscount(books));
    }
    
    public int getTotalSum(List<Book> books) {
        return books.stream()
                    .mapToInt(Book::getPrice)
                    .sum();
    }
    
    public double getDiscount(List<Book> books) {
        double discountRate = 0.5;
        return discountRate * books.stream()
                                   .sorted(Comparator.comparing(Book::getPrice, Comparator.reverseOrder()))
                                   .limit(2)
                                   .mapToInt(Book::getPrice)
                                   .sum();
    }
    

    Wit the above, it is now at first glance clear on which condition a discount is calculated.

    A few remarks: It is better when it comes to price or money in general to use the type double or even better BigDecimal instead of int. I'll leave it to you to improve that. Use List as parameter instead of a concrete implementation like ArrayList (Coding to an interface).