3

I am working on a framework where we are trying to convert our traditional loops to streams. My problem is I wrote two separate logics to get price and colors but I would like to merge both together so it will be presentable

Code to get the price values

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

Code to get the colors under 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 harcoded price in the above section to obtain the colors, instead, i would like to get that as input from the list of price values and get an output in

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

I tried merging these both without success, any help would be appriciated.

2
  • 1
    looks like some sort of groupingBy that you need... since you need a Map as a result Commented Aug 9, 2017 at 8:14
  • 2
    As a side note, never use double to express money values. You’ll find loads of articles on the net about it… Commented Aug 9, 2017 at 15:25

2 Answers 2

1

I would suggest you examine this or similar tutorial to get a bit of understanding how this works.

The key to the solution is to learn about Collectors.groupingBy() functionality. As a side note, there it also shows a better way of handling pricing information in Java.

But what you would 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 bit unclear about the details of classes involved, I assumed 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 possibility to filter and map colours in the mapping collector.

Sign up to request clarification or add additional context in comments.

Comments

1

You can first turn your second stream into a method that gets a List of products (assumed to be filtered/grouped by price) and transforms it to a List of 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 collector to gather all products by their price in a List and then with a second create a second stream and the productsToColors method get the map you want:

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 have groupingBy create a TreeMap instead so that the colors map will be sorted by price.

As a side-note beware of comparing double values for equality like this. You may want to round them first. Or use long variables multiplied by 100 (i.e. cents).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.