【问题标题】:How to remove duplicate key from a Hashmap如何从 Hashmap 中删除重复键
【发布时间】:2019-06-26 12:33:37
【问题描述】:

我有一个列表列表。列表中有一个列表。 [[-1, 0, 1], [-1, 2, -1], [0, 1, -1]],此列表的名称表示结果。结果列表包含重复元素作为列表。 [-1,0,1][0,1,-1] 它们是相同的。我想制作一个不包含重复项的列表。所以列表结果变为 [[-1,0,1],[-1,2,-1]][[-1,2,-1],[0,1,-1]]

我读到 Hashmap 不能存储重复键但允许重复值。因此,要删除重复项,我正在尝试使用 Hashmap。

但是写完代码后运行良好没有报错。

HashMap<List<Integer>,Integer> final_sol=new HashMap<>();
for(int k1=0;k1<result.size();k1++){
       final_sol.put(result.get(k1),k1);
    }
    System.out.println(final_sol);

输出:

{[-1, 2, -1]=1, [0, 1, -1]=2, [-1, 0, 1]=0}

编写此代码块后,我认为我的重复键不能只显示唯一键。

那我怎样才能使这个列表使用哈希映射唯一呢?Fail to understand

当我使用树形图时,它无法编译并给出一些错误。

【问题讨论】:

  • [-1,0,1][0,1,-1] 相同。 [-1,0,1][-1,0,1]' are the same. [0,1,-1]` 和 [0,1,-1] 是相同的。列表是有序的,因此在比较列表时值顺序很重要。 --- 如果要考虑[-1,1,0][0,1,-1] 相同,请先排序它们,使它们都变为[-1,0,1]然后添加到HashMap .
  • 此外,它还取决于您将什么用作 List 的具体类。我们无法从您给定的代码中知道,因为我们只能看到 List 界面 :) 但我假设您使用 ArrayList 所以我完全同意@Andreas。
  • @YavuzTas 即使原始列表不是ArrayList,您也可以在排序前复制到ArrayList,而原始列表保持不变。
  • @Andreas 当然,在这些情况下,复制可能是一种解决方法,所以我再次同意
  • [0, 1, 1] 是否与 [0, 0, 1] 或 [0, 1] 相同?

标签: java hashmap duplicates


【解决方案1】:

Maps确实不保留重复的key,Sets不保留重复的元素,但是你需要明白“duplicate”是根据keys/elementsequals()方法定义的,而基于hash的集合依赖于在其键/元素上具有与equals() 方法一致的hashCode() 方法。

现在你说

[-1,0,1][0,1,-1] 是一样的。

,但不,就Lists 的平等定义而言,它们相同。列表元素的顺序很重要,列表需要以反映这一点的方式实现equals()。这就是为什么这两个列表可能作为键出现在同一个 Map 中,并且两者都可能作为元素出现在同一个 Set 中。

那么我怎样才能使用哈希映射使这个列表唯一呢?

显然订单对您的目的而言重要,因此Lists 并不是真正适合您使用的模型。如果您不需要容纳重复的元素,那么您应该考虑使用 Sets 代替。标准库提供了几种实现,据我了解,其中HashSet 可能最适合您的情况。如果您确实需要容纳重复的元素,那么您正在寻找一个多重集。标准库不提供实现,但第三方提供了一些实现。

当我使用树形图时,它无法编译并给出了一些错误。

是的,它会的,除非您向它提供 Comparator 来确定元素的相对顺序。 TreeMap 将重复项识别为根据其自然顺序或 Comparator 指定顺序比较相等的键。

总体而言,听起来您想要一组集合或一组多重集合,而不是列表列表。我不明白你为什么要将地图带入其中。

【讨论】:

  • 不使用SetMultiset,您也可以只对List 元素进行排序,以获得一致的顺序,例如[-1,1,0][0,1,-1] 将变为相同,即 [-1,0,1]。由于顺序无关紧要,因此无论如何都不需要保留原始顺序。
  • 同意,@Andreas。然而,如果你想走这条路,那么你必须小心地做额外的工作来确保内部列表是有序的。这需要与保留列表形式的优势(如果有的话)进行权衡。
【解决方案2】:

试试这样的:

List<List<Integer>> result = Arrays.asList(
      Arrays.asList(-1, 0, 1),
      Arrays.asList(-1, 2, -1),
      Arrays.asList(0, 1, -1)
);
HashMap<Set<Integer>, List<Integer>> final_sol = new HashMap<>();

for (List<Integer> list : result) {
  final_sol.put(new HashSet<>(list), list);
}

System.out.println(final_sol.values());

您认为[-1,0,1][0,1,-1] 它们是相同的,但这不适用于列表,因为元素的顺序很重要。你需要集合来理解equals。

但即便如此,当[0,0,1][0,1,1] 相同时,它也可能不是您所期望的。在这种情况下,您必须将每个列表转换为一个 Map,它会为您提供原始列表中相同 Integer 的计数。

【讨论】:

  • 它正在工作。现在,如果我将这些值保存在列表列表中,我该如何保存它。函数返回类型public List&lt;List&lt;Integer&gt;&gt; threeSum(int[] nums) 。我应该以这种格式找出答案。
  • final_sol.values() 的结果是Collection&lt;List&lt;Integer&gt;&gt; 类型。您可以将其转换为这样的列表:List&lt;List&lt;Integer&gt;&gt; resList = new ArrayList&lt;&gt;(final_sol.values());.
【解决方案3】:

看来您可以通过Set&lt;Set&lt;Integer&gt;&gt; 在线完成此操作。这给了你[[-1, 0, 1], [-1, 2]];与[[-1, 0, 1], [-1, 2, -1]] 同态,但不是您想要的结果。以下是一组三个整数的向量,它们与任何排列比较相等,这与您的示例一致。根据documentation,覆盖equals 需要equivalence relation,并且必然需要hashCode,这样a == b -&gt; hashCode(a) == hashCode(b)

import java.lang.String;
import java.lang.Integer;
import java.util.Set;
import java.util.LinkedHashSet;

class Java {

    public static void main(String args[]) {
        Set<Three> set = new LinkedHashSet<>();
        set.add(new Three(-1, 0, 1));
        set.add(new Three(-1, 2, -1));
        set.add(new Three(0, 1, -1));
        System.out.printf("%s.\n", set);
    }

}

final class Three {
    private int a, b, c;
    public Three(final int a, final int b, final int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }
    @Override
    public int hashCode() { return a + b + c; }
    @Override
    public boolean equals(Object o) {
        if(this == o) return true;
        if(!(o instanceof Three)) return false;
        Three t = (Three)o;
        /* Brute force 3! = 6. */
        return a == t.a && b == t.b && c == t.c
            || a == t.a && b == t.c && c == t.b
            || a == t.b && b == t.a && c == t.c
            || a == t.b && b == t.c && c == t.a
            || a == t.c && b == t.a && c == t.b
            || a == t.c && b == t.b && c == t.a;
    }
    @Override
    public String toString() {
        return "["+a+","+b+","+c+"]";
    }
}

这会产生,

[[-1,0,1], [-1,2,-1]].

编辑:以下是上面代码的替换,用于替换一组三个整数的向量,当放入一个集合时,它们比较相等,这也与您的示例一致。

    /** Hashcode is the sum of the unique numbers. */
    @Override
    public int hashCode() {
        int h = a;
        if(a != b) h += b;
        if(c != a && c != b) h += c;
        return h;
    }
    @Override
    public boolean equals(Object o) {
        if(this == o) return true;
        if(!(o instanceof Three)) return false;
        Three t = (Three)o;
        /* t \in this && this \in t. */
        return (a == t.a || a == t.b || a == t.c)
            && (b == t.a || b == t.b || b == t.c)
            && (c == t.a || c == t.b || c == t.c)
            && (t.a == a || t.a == b || t.a == c)
            && (t.b == a || t.b == b || t.b == c)
            && (t.c == a || t.c == b || t.c == c);
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-28
    • 2017-10-08
    • 2011-08-30
    • 1970-01-01
    • 2017-03-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多