1

In addition to my question asked previously, that can be found here, How to combine list elements and find the price of largest combination

Instead of using Integer price, I am using String price,

List<Long> highest = details
                .stream()
                .map(d -> Stream.concat(Stream.of(d.getDetailId()), d.getStackableDetails().stream()).collect(Collectors.toList()))
                .collect(Collectors.toMap(s -> s.stream().map(Double.class::cast).reduce(0D,
                        (left, right) -> left + Double.parseDouble(map.get(right).getPrice())),
                        s -> s.stream().collect(Collectors.toList()),
                        (left, right) -> right,
                        TreeMap::new))
                .lastEntry().getValue();

But I keep getting a class cast exception while running the same. Can someone tell me why I'm not able to cast the Stream type and how I can rectify the same. Thanks!

Community
  • 1
  • 1
  • post the actual failure message/stacktrace – Eugene May 03 '17 at 10:35
  • java.lang.ClassCastException: Cannot cast java.lang.Long to java.lang.Double –  May 03 '17 at 10:39
  • yes, for example `String price ="30.0"`. –  May 03 '17 at 10:50
  • `detailId` is of type `Long` right? – Eugene May 03 '17 at 10:52
  • 1
    why are your types mixed up anyway? Is that `Detail.class` under your control? If yes, adapt it accordingly. If not: why don't you wrap them into your own type first? That way you don't need to cast and parse that often... – Roland May 03 '17 at 10:56
  • 1
    I added an [answer to your other question](http://stackoverflow.com/a/43763703/6202869), where you could just add your price transformation function into... – Roland May 03 '17 at 15:11

3 Answers3

2

Your problem is most probably here:

 s -> s.stream().map(Double.class::cast)

Your detailId is of type Long; but your are trying to convert that to a Double.

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • But isn't casting from long to double valid. Please let me know what I am missing, also is there an alternate way of doing this. –  May 03 '17 at 11:05
  • 1
    casting from the primitive type `long` to the primitive type `double` is valid, but casting from `Long` to `Double` is not, as `Long` is not a subclass of `Double`. You can use `.map(Long::doubleValue)` instead. – Holger May 03 '17 at 11:37
  • @liksar these are `Objects` and you can't simply cast from one to another (not going to explain why - there is *a lot* of info about this). Also you might be talking about `widening` or `narrowing` which works for simple types, not Objects. – Eugene May 03 '17 at 11:38
  • @Holger it is legal - but *might* very well lose precision, but the numbers would have to be really big. – Eugene May 03 '17 at 11:43
  • 1
    @Eugene: that doesn’t matter when you are going to sum them up to a `double` value anyway. Using the sum as a map key make little sense anyway, regardless of its type… – Holger May 03 '17 at 11:49
2

It’s not quite clear to me what you are trying to do, but there is no sense in populating a TreeMap, just to get the last element. Getting the maximum element is provided as an intrinsic Stream operation.

So what you are doing in the question’s code can be simplified to

List<Long> highest = details
    .stream()
    .map(d -> Stream.concat(Stream.of(d.getDetailId()), d.getStackableDetails().stream())
                    .collect(Collectors.toList()))
    .max(Comparator.comparingDouble(s -> s.stream()
                       .mapToDouble(l -> Double.parseDouble(map.get((double)l).getPrice()))
                       .sum()))
    .get();

This also fixes you problem by simply casting the Long to double. This will unbox the Long object to a long value, perform a widening conversion to double and box it to a Double for the Map lookup. However, it’s not recommended to use Double objects as map keys.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • Did I miss something? Where did the `map` come from (`map.get((double)l)`? – Roland May 03 '17 at 15:09
  • @Holger `TreeMap` suggestion was me being idiotic and writing and answer in a rush... Be to blame, not the OP – Eugene May 03 '17 at 15:32
  • 2
    @Roland: I don’t know where it comes from, but it’s in the OP’s code and I just use it exactly the same way… From the context, we can conclude that it must be a `Map`. Keep in mind that the OP’s code has evolved since the previous question. – Holger May 03 '17 at 15:47
  • 2
    @Eugene: never mind; we all do such things in a rush or when we are tired. That’s why it is so important to revise the code later on… – Holger May 03 '17 at 15:53
  • Eugene, Holger, Roland - Thanks for all the help folks, all these solutions work great. Thanks again! –  May 03 '17 at 16:03
  • ah, ok... wasn't there when I looked at it... so I was just wondering where I've missed it... thanks for the clarification. – Roland May 03 '17 at 16:05
1

Nearly a copy of my answer to your other question:

double maxPrice = details.stream()
  .mapToDouble(detail -> Stream.concat(Stream.of(detail.getDetailsId()),
                                       detail.getStackableDetails().stream())
    .flatMap(detailId -> details.stream()
      .filter(candidateDetail -> detailId.equals(candidateDetail.getDetailsId())))
    .map(Detail::getPrice)
    // the applied transformation function of your String price to double:
    .mapToDouble(Double::parseDouble) 
    .sum()
  )
  .max()
  .orElse(0.0);
Community
  • 1
  • 1
Roland
  • 22,259
  • 4
  • 57
  • 84