【问题标题】:Create a TreeMap from nested list using Java Streams使用 Java Streams 从嵌套列表创建 TreeMap
【发布时间】:2019-01-11 10:06:53
【问题描述】:

鉴于: 我有List<List<Integer>> locations,这是一个位置的坐标。例如,地点 A:(2,4),地点 B:(5,4),地点 C:(10,9),地点 D:(2,4)。所以我的locations 将包含列表列表。 我无法更改此格式。

前往特定位置的成本是坐标总和的平方根。所以去的代价是Place A = Math.sqrt(2 + 4),去的代价是Place B = Math.sqrt(5 + 4)等等。

输出:我想要得到的是所有位置中“成本最低”的列表。退货要求为List<List<Integer>> nearestLocations。我所做的是我正在尝试创建一个TreeMap<Double, List<List<Integer>>

问题我的问题是如何使用 Java 8 流转换下面的转换?

 List<List<Integer>> findNearestLocation(int total, List<List<Integer>> allLocations, int size) {
        ArrayList<List<Integer>> results = new ArrayList<>();
        TreeMap<Double, List<Integer>> map = new TreeMap<>();
        for (int i = 0; i < total && i < allLocations.size(); i++) {
            List<Integer> list = allLocations.get(i);
            double l = 0.0;
            for (Integer x : list) {
                l += x * x;
            }
            map.put(Math.sqrt(l), list);
        }
        if (map.size() > 0) {
            for (int get = 0; get < size; get++) {
                results.add(map.get(map.firstKey()));
                map.remove(map.firstKey());
            }

        }
        return results;
    }

【问题讨论】:

  • 您的解决方案似乎计算了一个映射,其中键是实际成本,而您似乎希望能够通过place 进行查找。另外,在您的初始List&lt;List&lt;Integer&gt;&gt; locations 输入中定义的“地点”在哪里?外部列表中的索引?
  • “地点”只是输入以这种方式构造的伪含义。它实际上只是一个List&lt;List&lt;Integer&gt;&gt; locations。没有 Place 对象。 @ernest_k
  • “我可以通过多个 for each 的多次迭代来做到这一点” - 您如何发布该代码,以便我们更容易理解您到底在寻找什么?
  • @daniu 我已经添加了手动迭代
  • 等等,你只想按元素的平方根对列表进行排序?

标签: java algorithm java-8 java-stream treemap


【解决方案1】:

你的Map实际上是Map&lt;Double, List&lt;Integer&gt;&gt;

如果你需要TreeMap,你当前的代码只返回Map

    TreeMap<Double, List<List<Integer>>> x = locations.stream().collect(
            Collectors.groupingBy((List<Integer> b) -> {
                        double d = b.stream().mapToDouble(i -> i.doubleValue()).sum();
                        return Math.sqrt(d);
                    },
                    TreeMap::new,
                    Collectors.toList()));

PS:你的距离不是通常的欧式距离。要做到这一点,您需要i -&gt; i.doubleValue() * i.doubleValue()

【讨论】:

  • 我看到你抛出了一个运行时异常,我需要返回值是 List> 作为返回类型,所以在碰撞时我试图追加列表而不是抛出 RunTimeException
  • @mel3kings 解决了这个问题。
  • locations.stream().collect( Collectors.groupingBy(b -&gt; Math.sqrt(b.stream().mapToDouble(Integer::doubleValue).sum()), TreeMap::new, Collectors.toList()));
  • 您应该将乘法插入代码中,而不是事后才提及。您可以像.mapToDouble(i -&gt; i * i) 一样简单地进行操作,或者,如果您担心整数溢出,请使用.mapToDouble(i -&gt; i * (double)i)。顺便说一句,当您仅使用该值进行排序时,无需计算 sqrt
【解决方案2】:

如果您只想按距离对列表进行排序,您可以这样做

Collections.sort(list, (list1, list2) -> 
    Double.compare(Math.sqrt(list1.get(0) + list1.get(1)),
                   Math.sqrt(list2.get(0) + list2.get(1))));

如果初始列表是不可变的,则在列表的副本上。

【讨论】:

  • 我认为你非常接近。检查this comment。我认为您只需要在排序后返回一个子列表
  • @ernest_k 是的,我注意到了,但是 a) 这不在实际的问题陈述中,并且 b) 在结果上调用 sublist 有点微不足道。
  • 当您使用带有花括号的 lambda 语法时,您需要一个 return 语句。对于表达式语法,删除 {}。实际上,您需要sqrt(x*x + y*y) 而不是sqrt(x + y)。但另一方面,要确定排序,您可以省略昂贵的sqrt 计算,因为它不影响排序。所以你可以使用Collections.sort(list, Comparator.comparingInt(l -&gt; l.get(0)*l.get(0) + l.get(1)*l.get(1)));
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多