【问题标题】:How to combine list elements and find the price of largest combination如何组合列表元素并找到最大组合的价格
【发布时间】:2017-05-02 09:24:57
【问题描述】:

我有一个类包含特定项目的详细信息,如下所示:

Detail.class

Long detailsId;
Integer price;
List<Long> stackableDetails;

/*getters and setters*/

现在,我有一个如下示例数据集:

    DetailId    Price    StackableDetails
------------------------------------------
    1011        4$       1012, 1014
    1012        6$       1011,1013
    1013        10$      1012
    1014        8$       1011

此数据集映射到 List sampleDetails。 现在,根据 stackableDetails 信息,我必须组合详细信息并从中选择具有最高价格的组合。

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$

现在详细信息 1012,1011,1013 的组合产生 20 美元,因此我获取此组合并将其添加到我的结果列表中。如何在 java8 中实现这一点。

任何帮助表示赞赏。谢谢!

【问题讨论】:

  • 您能否说明您希望如何进行组合以及如何选择“最佳”组合?
  • 组合将基于 StackableDetails 中的值,并根据价格值的最高总和选择最佳组合。
  • 您没有提供足够的信息来确定它是否是完美的复制品,但信息 here 应该可以帮助您
  • 我想到的唯一解决方案是先通过并将所有 detailId、价格存储在地图中。在第二遍中,这次遍历 stackabledetails 列表,并通过每次从地图中提取价格来生成总和。我不确定这是否可行,您有什么建议吗?
  • 您能详细说明完美复制的含义吗?

标签: collections java-8 java-stream


【解决方案1】:

嗯,首先它有点误导。在你的问题中你说pick the combination having the least price from it,但后来(和你的cmets)你实际上提供了产生max结果的样本。

假设你需要最大结果,你可以使用这个:

 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

编辑

您想通过max price 进行比较,但输出set 是这个价格。我唯一能想到的是将它们放入TreeMap,但这不是可读性恕我直言。此外,有时您的条目发生冲突 - 它们具有相同的最高价格。此示例仅按遇到顺序取最后一个。

  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));

【讨论】:

  • 感谢您指出,我已经更正了。非常感谢这个解决方案,如果我要获得相应的细节元素组合(并存储在结果列表中)而不是组合的总和。我该怎么做呢?
  • @liksar 你希望结果是 1012,1011,1013 而不是 20?
  • 我希望将结果保存在 List bestDetails 中。所以 bestDetails 会有 3 个 Detail 对象对应 DetailIds - 1012, 1011, 1013
  • @liksar 让我们以four details 为例。你到底想从中得到什么?价格为max 的单个详细信息,排序的详细信息列表?等等?你能再详细点吗?
  • @liksar 参见 EDIT2。这是我在这里所做的最后一次编辑,请将您的问题作为新问题发布。您不仅可以使其更清晰,还可以帮助其他人。
【解决方案2】:

看着尤金斯的回答,我认为这应该也能工作更短一些...这是另一个使用 flatMapmapToDouble 以及 DoubleStreamsummax 的变体:

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);

我想知道,为什么您只能总结细节及其直接可堆叠的细节。对我来说这听起来像是一个递归问题,但另一方面,你可能知道,你需要什么 :-)

关于your other question:您可能只想将转换步骤替换为以下内容:

.mapToDouble(Double::parseDouble)

请注意,您可以将double/mapToDouble 等换成最适合您的东西。 sum() 但仅适用于三个原始流:IntStreamLongStreamDoubleStream

【讨论】:

    猜你喜欢
    • 2022-01-20
    • 1970-01-01
    • 2016-08-15
    • 1970-01-01
    • 2021-01-13
    • 2013-09-03
    • 2011-01-25
    • 2021-06-15
    • 1970-01-01
    相关资源
    最近更新 更多