【问题标题】:LinkedHashMap<double[], Integer>, cannot access Integer with .get or .containsKeyLinkedHashMap<double[], Integer>,无法使用 .get 或 .containsKey 访问 Integer
【发布时间】:2017-06-29 22:43:46
【问题描述】:

我有一系列小数组(由两个双精度组成),其中许多是 相同。例如

{5.0, 15.0}
{5.0, 15.0}
{5.0, 15.0}
{12.0, 8.0}
{10.0, 8.0}
{10.0, 8.0}

我希望能够计算每个数组的数量,即

3 of {5.0, 15.0}
1 of {12.0, 8.0}
2 of {10.0, 8.0}

为此,我尝试使用 LinkedHashMap(链接,因为订单 以后可能会用到):

import java.util.Map;
import java.util.LinkedHashMap;

public class MapArrayInt {
        Map<double[], Integer> arrays = new LinkedHashMap<double[], Integer>();

    public static void main(String[] args) {
        MapArrayInt mapArrayInt = new MapArrayInt();
        mapArrayInt.addArray(5.0, 15.0);
        mapArrayInt.addArray(5.0, 15.0);
        mapArrayInt.addArray(5.0, 15.0);
        mapArrayInt.addArray(12.0, 8.0);
        mapArrayInt.addArray(10.0, 8.0);
        mapArrayInt.addArray(10.0, 8.0);
        System.out.println(String.valueOf(mapArrayInt.arrays.get(new double[]{5.0, 15.0})));
        System.out.println(String.valueOf(mapArrayInt.arrays.get(new double[]{12.0, 8.0})));
        System.out.println(String.valueOf(mapArrayInt.arrays.get(new double[]{10.0, 8.0})));
    }

    void addArray(double val1, double val2) {
        double[] newArray = new double[]{val1, val2};
        if (!arrays.containsKey(newArray)) {
            arrays.put(newArray, 1);
        } else {
            arrays.put(newArray, arrays.get(newArray) + 1);
        }
    }
}

我期待这个输出,

3
1
2

但是得到了,

null
null
null

我对 Java 很陌生,但我怀疑这可能是因为每个 double[] 都算作唯一的,因为它们是不同的实例,即使它们包含相同的两个双精度值。

如果我应该解决这个问题,我该如何解决(有没有更好的方法)?我只需要一个数据结构,让我能够

  1. 添加doubles[]
  2. 保留doubles[] 的顺序
  3. 轻松迭代以获取doubles[] 和所说doubles[] 的数量

【问题讨论】:

  • 你是对的,为什么你会遇到这个问题,但你能解释一下这是什么for吗?在浮点上进行等式比较(例如查找)通常是个坏主意。
  • 你能用List&lt;Double&gt;代替double[]吗?
  • @chrylis A map 代表一个练习;每个double[] 代表每个练习的一组,其中val1 是代表次数,val2 是使用的重量值。通过检索具有相同值的double[]s 的数量,我可以轻松打印出类似3x8 reps of 20kg 的内容,其中3 是具有值820 的双精度数。
  • 每次向地图添加内容时,都会添加一个 double[] 数组。当您尝试通过arrays.get(new double[]{5.0, 15.0}) 从中接收值时,您也在创建一个 new 数组,该数组与地图中的引用不同。因此,您在尝试检索条目时会收到​​ null
  • @ning 从技术上讲,任何需要数组的用例都可以用列表代替。

标签: java arrays data-structures hashmap linkedhashmap


【解决方案1】:

正如我在评论中所说,使用new 您正在创建一个对象的新实例。这意味着您使用mapArrayInt.addArray(5.0, 15.0); 添加的数组和mapArrayInt.arrays.get(new double[]{5.0, 15.0}) 中的数组引用不同的 对象。这就是你得到null 的原因,因为对于地图来说,它们是不同的键。

为了避免这种情况,您可以创建一个自定义包装类

import java.util.Arrays;
public class Exercise {
    private final double[] array;
    public Exercise(double first, double second) {
        this.array = new double[]{first, second};
    }

    public boolean equals(Object obj) {
        if(!(obj instanceof Exercise)) {
            return false;
        }
        Exercise other = (Exercise)obj;
        return Arrays.equals(this.array, other.array);
    }

    public int hashCode() {
        return Arrays.hashCode(array);
    }
}

equalshashCode 方法很重要,当你想在像 Map 这样的集合中使用这个类时,否则 Object 的哈希码用于检查相等性,你会遇到同样的问题你现在有。

然后,在你的主类中,你可以像这样使用它:

void addArray(double val1, double val2) {
    Exercise exercise = new Exercise(val1, val2);
    if (!arrays.containsKey(exercise)) {
        arrays.put(exercise, 1);
    } else {
        arrays.put(exercise, arrays.get(exercise) + 1);
    }
}

还有System.out.println(String.valueOf(mapArrayInt.arrays.get(new Exercise(5.0, 15.0))));

【讨论】:

  • 我认为这就是我正在寻找的答案。因此,在数组上使用静态hashCode 方法将为具有相同值/内容的数组的两个不同实例返回相同的值,这样map.containsKey 是否有效?为什么正常Arrays 默认情况下不会发生这种情况?
  • 我刚刚做了下面几乎相同的示例。在这种情况下(我的示例)是否更喜欢覆盖 equalshashCode 而不是提供单个实例?
  • 没关系,我找到了关于 hashCode 的一个很好的答案on another thread
  • 如果您要创建一个单独的类,请完全放弃数组并使用有意义的变量名。
【解决方案2】:

编辑: 我将其中一个双打更改为 int (你说你代表代表次数和重量......并且次数只能是自然数对吗?)

您可以像下面这样创建一个练习类,并使用静态方法“of”来创建实例:

package somepackage;

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;

public class Exercise
{
    private static final Map<Integer, Map<Double, WeakReference<Exercise>>> instances = new HashMap<>();

    private final int reps;
    private final double weight;

    private Exercise(int reps, double weight)
    {
        this.reps = reps;
        this.weight = weight;
    }

    public static Exercise of(int reps, double weight)
    {
        if (!instances.containsKey(reps))
        {
            instances.put(reps, new HashMap<>());
        }

        Map<Double, WeakReference<Exercise>> innerMap = instances.get(reps);
        WeakReference<Exercise> weakRef = innerMap.get(weight);
        Exercise instance = null;

        if (weakRef != null)
        {
            instance = weakRef.get();
        }

        if (weakRef == null || instance == null || weakRef.isEnqueued())
        {
            instance = new Exercise(reps, weight);
            innerMap.put(weight, new WeakReference<>(instance));
        }

        return instance;
    }

    public int getReps()
    {
        return this.reps;
    }

    public double getWeight()
    {
        return this.weight;
    }
}

然后你可以把这些练习放在下面的地图中:

public void addArray(int reps, double weight)
{
    Exercise exercise = Exercise.of(reps, weight);
    if (!arrays.containsKey(exercise))
    {
        arrays.put(exercise, 1);
    }
    else
    {
        arrays.put(exercise, arrays.get(exercise) + 1);
    }
}

或者: 您可以使用 Map&lt;Double, Integer&gt; 作为 2 个值的值,而不是 double[] 作为键:

package somepackage;

import java.util.HashMap;
import java.util.Map;

public class MapArrayInt
{
    private final Map<Double, Map<Double, Integer>> values;

    public MapArrayInt()
    {
        this.values = new HashMap<>();
    }

    public void addArray(double val1, double val2)
    {
        if (!this.values.containsKey(val1))
        {
            this.values.put(val1, new HashMap<>());
        }

        Map<Double, Integer> innerValues = this.values.get(val1);
        if (innerValues.containsKey(val2))
        {
            innerValues.put(val2, innerValues.get(val2) + 1);
        }
        else
        {
            innerValues.put(val2, 1);
        }
    }

    public int getArrayValue(double val1, double val2)
    {
        Map<Double, Integer> innerValues = this.values.get(val1);
        if (innerValues == null)
        {
            // you may also throw an Exception here
            return 0;
        }

        Integer value = innerValues.get(val2);
        if (value == null)
        {
            // also here you may throw an Exception
            return 0;
        }

        return value;
    }

    public int getArrayValue(double[] values)
    {
        return getArrayValue(values[0], values[1]);
    }
}

【讨论】:

  • 不,使用包装类。它不那么复杂,并且可以扩展到任意长度的数组。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-12-19
  • 1970-01-01
  • 2021-09-30
  • 2015-02-19
  • 1970-01-01
  • 1970-01-01
  • 2021-11-09
相关资源
最近更新 更多