Java streams generating map issue

I am working on a framework where we are trying to convert our traditional loops to streams. My problem is that I wrote two separate logics to get the price and colors, but I would like to combine them together so that they are presentable

Code for getting price values

List<Double> productPrices = product.getUpcs()
            .stream()
            .map(e -> e.getUpcDetails().getPrice().getRetail().getPriceValue())
            .distinct()
            .sorted(Comparator.reverseOrder())
            .collect(Collectors.toList());

      

Code for getting flowers at prices

      product.getUpcs()
            .stream()
            .filter(e -> e.getUpcDetails().getPrice().getRetail().getPriceValue() == 74.5)
            .flatMap(e -> e.getUpcDetails().getAttributes().stream())
            .filter(e2 -> e2.getName().contentEquals("COLOR"))
            .forEach(e3 -> System.out.println(e3.getValues().get(0).get("value")));

      

I calculated the price in the above section to get the colors, instead I would like to get this as input from a list of price values ​​and get the result in

Map<Double,List<colors>
output Map<75.4, {blue,black,orange}> 

      

I tried to combine these both with no success, any help would be appriciated.

+3


source to share


2 answers


I would suggest that you study this or a similar tutorial to get a little understanding of how it works.

The key to the solution is to become familiar with the functionality Collectors.groupingBy()

. As a side note, it also shows the best way to handle pricing information in Java.

But what you need to do is something like this:

 Map<Double, Set<String>> productPrices = product
            .stream()
            .map(e -> e.getUpcDetails())
            .collect(
                    Collectors.groupingBy(Details::getPrice,
                    Collectors.mapping(Details::getColors, Collectors.collectingAndThen(
                            Collectors.toList(),
                            (set) -> set
                                    .stream()
                                    .flatMap(Collection::stream)
                                    .collect(Collectors.toSet())))

            ));

      



Since your question is a little unclear about the details of related classes, I adopted this simple class structure:

class Details {
    private double price;
    private List<String> colors;

    double getPrice() { return price; }
    List<String> getColors() { return colors; }
}

class Product {
    private Details details;

    Details getUpcDetails() { return details; }
}

      

``,

It would be possible to optimize the code above, but I specifically left the ability to filter and display colors in the card collector.

+1


source


First, you can turn your second stream into a method that gets the List

products (assuming they are filtered / grouped by price) and converts it to List

colors:

List<Color> productsToColors(final List<Product> products) {
    return products.stream()
        .flatMap(e -> e.getUpcDetails().getAttributes().stream())
        .filter(e2 -> e2.getName().contentEquals("COLOR"))
        .map(e3 -> e3.getValues().get(0).get("value"))
        .collect(toList());
}

      

You can use the groupingBy collection to collect all products at their price in List

, and then with a second create a second thread and the method productsToColors

gets the desired card:



Map<Double, List<Color>> colors = product.getUpcs().stream()
    .collect(groupingBy(e -> e.getUpcDetails().getPrice().getRetail().getPriceValue())
    .entrySet().stream()
    .collect(toMap(Entry::getKey, e -> productsToColors(e.getValue())));

      

You can also groupingBy

create TreeMap

a color map to be sorted by price.

As a side note, beware of comparing double values ​​for such equality. You might want to round them up first. Or use long variables multiplied by 100 (i.e. Cents).

+1


source







All Articles