此方法获取一个所有值都等于null的Map,并返回具有相同键的SortedMap,并带有新值(通过ObjectiveFitness获得)

步骤1.首先,我从输入Map中获取键,并使用相同的键构造一个新的HashMap,新值是ObjectiveFitness(key)。

public SortedMap<Integer[], Integer> evaluate(Map<Integer[], Integer> population, Integer[] melody, Integer[] mode) {

    Map<Integer[], Integer> fitPop = new HashMap<>();
    fitPop = population.keySet() //you just have the keys.
            .stream()
            .collect(Collectors.toMap(p -> p, p -> this.objectiveFitness(p)));

步骤2。下一步是使用Stream使用自定义的Comparator将HashMap中的所有条目收集到SortedMap中。

从Oracle网站阅读以下内容:http://docs.oracle.com/javase/tutorial/collections/interfaces/order.html

...我发现,由于我想基于除条目自然排序之外的其他方法来维持SortedMap的排序性,因此我需要实现一个由两部分组成的Comparator。我将根据适应度值进行排序,使用该键比较唯一性。 *此外,我希望2个值可以相似,但是我不想

其中一部分与排序有关,并根据值返回(1,0或-1)。比较器的另一部分与唯一性有关(因为Maps不允许重复。这是到目前为止我最好的镜头,但是我很努力。
    Comparator<Map.Entry<Integer[], Integer>> fitnessOrder =
                                new Comparator<Map.Entry<Integer[], Integer>>() {
            public int compare(Map.Entry<Integer[], Integer> m1, Map.Entry<Integer[], Integer> m2) {
            int fitCmp = m2.getValue().compareTo(m1.getValue());
            if (fitCmp != 0)
                return fitCmp;


            if(m1.getKey().equals(m2.getKey())) return 0;
                for(int i = 0; i < m1.getKey().length; i++){
                    if(m1.getKey()[i] > m2.getKey()[i]){
                        return 1;
                    }
                    if(m1.getKey()[i] < m2.getKey()[i]){
                        return -1;
                }
            }
            return 0;
            }
            };

看起来和equals一致吗?我真的不知道如何实现它。

如果是正确的话,我想使用上面的Comparator帮助我使用lambda收集到TreeMap中,但是我只是一遍又一遍地陷入困境。

我还看着:Java TreeMap Comparator
我看到了有关基于键排序SortedMap的注释,因为它使用了NavigableMap并因此对键进行排序,否则由比较器进行排序。如果不使用SortedSet,真的没有好的方法吗?
    SortedMap<Integer[], Integer> sortedFitPop = fitPop.entrySet()
            .stream()
          //now I want to insert entries into the TreeMap
          //with sortedness according to the Comparator above
            .collect(Collectors.toCollection((k,v) -> (k,v), new TreeMap(fitnessOrder)
   ));

键应该仍然是键,值仍然应该是它们在HashMap中的值,但是现在在收集时,我希望TreeMap应该始终从头开始并且在每次输入后都进行排序。

是的,当然最好不要收集到HashMap中进行启动,而且我觉得有一种方法可以使用Java-8 / streams / lambdas进行整洁。

先感谢您!我想非常了解这个东西!

最佳答案

作为already said by Flown,无法创建按值排序的TreeMap。想一想。当 map 需要该查询的结果来确定其在 map 中的位置时,该如何实现查询?仅当所有 map 操作降级为整个 map 的线性搜索或更糟时,这才起作用。

您自己已经提到了另一个问题:与equals的一致性。使用映射值的比较器不能与键的equals保持一致,但是即使专用于Integer[]键的比较器也不能与equals保持一致,因为Java数组没有equals方法。这在使用时也会引起您的注意LinkedHashMap,并在插入前按值排序。在这种情况下,由于数组没有适当的hashCodeequals实现,因此查找仅适用于相同的数组对象实例,而不适用于等效的元素序列。

考虑到这一点,您无论如何都不应使用Integer[]数组。泛型不支持基本类型,但基本类型的数组不是基本类型,这可能使您感到困惑。因此,没有理由不在此处使用int[]

使用int[]数组时,可以使用IntBuffer对其进行包装,从而获得一种类型,该类型根据Comparable的内容一致地实现hashCodeequalsint[]。然后,您可以从已排序的流中创建LinkedHashMap。只要您以后不修改 map ,它就会反映流元素的遇到顺序,这将是所需的顺序。

// convert int[] arrays to IntBuffer via IntBuffer.wrap first
public Map<IntBuffer, Integer> evaluate(Map<IntBuffer, Integer> population, …) {
  Map<IntBuffer, Integer> fitPop = population.keySet().stream()
    .map(ia -> new AbstractMap.SimpleImmutableEntry<>(ia, objectiveFitness(ia.array())))
    .sorted(Map.Entry.<IntBuffer,Integer>comparingByValue()
            .thenComparing(Map.Entry.comparingByKey()))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
            (a,b)->{ throw new IllegalStateException(); }, LinkedHashMap::new));
  return fitPop;
}

看到这一点,您可能会考虑从整数数组到整数的映射是否确实是总体的适当表示。当为持有身份标准和当前适应度的人口成员创建专用类型时,您可以摆脱所有这些障碍。这些人口成员的简单列表或数组就足以代表一个人口。重新计算适应度将是一个简单的forEach操作,并且根据适应度属性对列表或数组进行排序也很容易(您无需考虑具有相同适应度的元素的顺序,因为使用数组或列表中的适应度相同)。

10-06 14:41
查看更多