问题
I have a class that holds details of a particular item like the following:
Detail.class
Long detailsId;
Integer price;
List<Long> stackableDetails;
/*getters and setters*/
Now, I have a sample dataset like the following:
DetailId Price StackableDetails
------------------------------------------
1011 4$ 1012, 1014
1012 6$ 1011,1013
1013 10$ 1012
1014 8$ 1011
This data set maps to List sampleDetails. Now, based on the stackableDetails information, I have to combine the details and pick the combination having the max price from it.
For eg,
In the data set available, the possible combinations would be
1011,1012,1014 - 4+6+8 = 18$
1012,1011,1013 - 6+4+10 = 20$
1013,1012 - 10+6 = 16$
1014,1011 - 8+4 = 12$
Now the combination of details 1012,1011,1013 yields 20$, so I fetch this combination and add this in my result list. How can I achieve this in java8.
Any help appreciated. Thanks!
回答1:
Well, first it's a bit misleading. In your question you say pick the combination having the least price from it
, but then later (and your comments) you actually provide the samples that yields the max
result.
Assuming you need the max result, you could use this:
long maxPrice = list
.stream()
.map(d -> Stream.concat(Stream.of(d.getDetailsId()), d.getStackableDetails().stream()))
.map(s -> s.reduce(0L, (left, right) -> left +
list.stream()
.filter(dt -> dt.getDetailsId().equals(right))
.findAny()
.get()
.getPrice()))
.max(Comparator.naturalOrder())
.orElse(0L);
System.out.println(maxPrice); // 20
EDIT
Well you want to compare by max price
, but output set
the make this price. The only thing I could come up with is to put them into a TreeMap
, but that is not very readable IMHO. Also, there is the case when you have entries that collide - they have the same max price. This example simply takes the last one in encounter order.
List<Long> highest = list
.stream()
.map(d -> Stream.concat(Stream.of(d.getDetailsId()), d.getStackableDetails().stream()).collect(Collectors.toList()))
.collect(Collectors.toMap(s -> s.stream().reduce(0L,
(left, right) -> left + list.stream().filter(dt -> dt.getDetailsId().equals(right)).findAny().get().getPrice()),
s -> s.stream().collect(Collectors.toList()),
(left, right) -> right,
TreeMap::new))
.lastEntry().getValue();
EDIT2
Map<List<Long>, Long> map = list
.stream()
.map(d -> Stream.concat(Stream.of(d.getDetailsId()), d.getStackableDetails().stream()).collect(Collectors.toList()))
.collect(Collectors.toMap(
s -> s.stream().collect(Collectors.toList()),
s -> s.stream().reduce(0L,
(left, right) -> left + list.stream().filter(dt -> dt.getDetailsId().equals(right)).findAny().get().getPrice()),
(left, right) -> right));
回答2:
Looking at Eugenes answer I thought that should work also a bit shorter... Here is another variant using flatMap and mapToDouble and the DoubleStream's sum and max:
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)
.mapToDouble(value -> /* your transformation function */ (double) value)
.sum()
)
.max()
.orElse(0.0);
I wonder, why you might only sum up the details and its immediate stackable details. It sounds like a recursive problem to me, but on the other side, you probably know, what you need :-)
Regarding your other question: you may just want to replace the transformation step into the following:
.mapToDouble(Double::parseDouble)
Note that you can exchange double/mapToDouble
, etc. to whatever suits you the most. sum()
however is only available to the three primitive streams: IntStream
, LongStream
and DoubleStream
.
来源:https://stackoverflow.com/questions/43734400/how-to-combine-list-elements-and-find-the-price-of-largest-combination