Java HashSet使用指定方法

发布于 2024-10-10 03:40:54 字数 877 浏览 0 评论 0原文

我有一个基本类“HistoryItem”,如下所示:

public class HistoryItem
  private Date startDate;
  private Date endDate;
  private Info info;
  private String details;

  @Override
  public int hashCode() {
    int hash = (startDate == null ? 0 : startDate.hashCode());
    hash = hash * 31 + (endDate == null ? 0 : endDate.hashCode());
    return hash;
  }
}

我当前正在使用 HashSet 从 startDate & 上的 ArrayList 中删除重复项。 endDate 字段,工作正常。

但是,我还需要删除不同字段(信息和详细信息)上的重复项。

我的问题是这样的。
有没有办法指定 HashSet 将使用不同的方法来代替 hashCode()? 像这样的事情:

public int hashCode_2() {
  int hash = (info == null ? 0 : info.hashCode());
  hash = hash * 31 + (details == null ? 0 : details.hashCode());
  return hash;
}

Set<HistoryItem> removeDups = new HashSet<HistoryItem>();
removeDups.setHashMethod(hashCode_2);

或者我应该采取另一种方式吗?

I have a basic class 'HistoryItem' like so:

public class HistoryItem
  private Date startDate;
  private Date endDate;
  private Info info;
  private String details;

  @Override
  public int hashCode() {
    int hash = (startDate == null ? 0 : startDate.hashCode());
    hash = hash * 31 + (endDate == null ? 0 : endDate.hashCode());
    return hash;
  }
}

I am currently using a HashSet to remove duplicates from an ArrayList on the startDate & endDate fields, which is working correctly.

However I also need to remove duplicates on different fields (info & details).

My question is this.
Is there a way to specify a different method which HashSet will use in place of hashCode()?
Something like this:

public int hashCode_2() {
  int hash = (info == null ? 0 : info.hashCode());
  hash = hash * 31 + (details == null ? 0 : details.hashCode());
  return hash;
}

Set<HistoryItem> removeDups = new HashSet<HistoryItem>();
removeDups.setHashMethod(hashCode_2);

Or is there another way that I should be doing this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

何以畏孤独 2024-10-17 03:40:54

您可以使用不同的 GetHashCode 实现围绕 HistoryItem 创建一个包装器类,然后围绕原始集合中的每个项目创建一个包装器的 HashSet。

You can make a wrapper class around HistoryItem with a different GetHashCode implementation, then make a HashSet of wrappers around each item in the original set.

荭秂 2024-10-17 03:40:54

有几件事。首先也是最重要的,如果要重写 hashCode(),则必须重写 equals()。这很重要。其次,如果您正在处理不同的字段,那么您可能应该为每个字段使用不同的 HashSet。所以你可以像这样迭代 Map:

HashSet<String> info;
HashSet<String> details;
for (HistoryItem h:map){
  if(info.contains(h.getInfo()){
    // this is a dup

  }
  if (details.contains(h.getDetails()){
    // this is a dup
  }
  info.add(h.getInfo());
  details.add(h.getDetails());
}

A couple things. First and foremost, you MUST override equals() if you are going to override hashCode(). This is important. Second, if you are dealing with different fields, then you should probably have a different HashSet for each field. So you can iterate over the Map like so:

HashSet<String> info;
HashSet<String> details;
for (HistoryItem h:map){
  if(info.contains(h.getInfo()){
    // this is a dup

  }
  if (details.contains(h.getDetails()){
    // this is a dup
  }
  info.add(h.getInfo());
  details.add(h.getDetails());
}
请别遗忘我 2024-10-17 03:40:54

我最终使用了 GNU Trove 来实现此目的。

需要最少的代码更改。

实现 TObjectHashingStrategy 的新类(包含 HashCodeEquals 方法)。

public class HistoryItemDuplicateInfo
implements TObjectHashingStrategy<HistoryItem> {

  @Override
  public int computeHashCode(HistoryItem obj) {
     ...
  }

  @Override
  public boolean equals(HistoryItem arg0, HistoryItem arg1) {
    ...
  }
}

然后使用 THashSet 对象以及指定的策略来删除重复项。

THashSet<HistoryItem> hs = new THashSet<HistoryItem>(new HistoryItemDuplicateInfo());

希望这能够帮助将来的人。

I ended up using GNU Trove for this.

Minimal code change was required.

A new class implementing TObjectHashingStrategy (containing HashCode and Equals methods).

public class HistoryItemDuplicateInfo
implements TObjectHashingStrategy<HistoryItem> {

  @Override
  public int computeHashCode(HistoryItem obj) {
     ...
  }

  @Override
  public boolean equals(HistoryItem arg0, HistoryItem arg1) {
    ...
  }
}

Then use the THashSet object with a specified strategy for removing the duplicates.

THashSet<HistoryItem> hs = new THashSet<HistoryItem>(new HistoryItemDuplicateInfo());

Hope this is able to help someone out in future.

池木 2024-10-17 03:40:54

您可以使用 java.util.TreeSet 和自定义 Comparator 来删除重复项,该自定义 Comparator 会获取您的 InfoDetails考虑到。

You could remove the duplicates using a java.util.TreeSet with a custom Comparator that takes your Info and Details into account.

唯憾梦倾城 2024-10-17 03:40:54

我建议你;

  • 使用 long 作为日期而不是 Date 对象。
  • 如果您想避免重复,请仅使用 Set。你为什么要使用列表?如果您需要使用 TreeSet 等 SortedSet 或 LinkedHashSet 等保留顺序的 Set 来保留顺序。
  • 您的 HistoryItem 是否可以为空字段有效?你能构造你的字段,让它们永远不为空吗?
  • 组成 hashCode/equals/compareTo 的字段应该是不可变的。这些字段可以是最终的吗?如果没有,为什么不呢?

I would suggest you;

  • use long for a date instead of a Date object.
  • use just a Set if you want to avoid duplicates. Why are you using a List at all? If you need to retain a order using a SortedSet like TreeSet or a Set which retains order like LinkedHashSet.
  • Can your HistoryItem be valid will null fields? Can you structure your fields so they are never null?
  • Fields which make up hashCode/equals/compareTo should be immutable. Can those fields be final? If not, why not?
述情 2024-10-17 03:40:54

HashSet 被硬编码为使用 hashCode()equals()。您可以通过无情地复制 Java 自己的源代码来实现您自己的类似 HashSet 的类,但这非常丑陋,与任何像样的软件开发规则集相矛盾,并且对于 Java 源代码来说可能是非法的许可证(这取决于实际的 JDK,例如 Sun/Oracle 的 JDK 与 OpenJDK)。

不过,您可以使用 TreeSet 做一些事情。 TreeSet 通常使用元素的 compareTo() 方法,使用 hashCode()equals ()。此外,可以使用自定义的 Comparator 实例构建 TreeSet 实例,然后调用该实例进行比较,从而使您可以自由地拥有自己的规则。 compareTo() 方法(或 Comparator.compare() 方法)必须实现一个 order,这可能比简单的hashCode()-和-equals(),但这通常也不难。有时据说 TreeSetHashSet 慢,但实际差异很小,并且需要非常具体的情况才能真正以任何方式注意到这种差异。

从概念上讲,HashSet 可能有一个相当于 Comparator 的哈希:带有 int hashCode(Object obj) 的接口 HasherAndEqualizer > 和 boolean equals(Object obj1, Object obj2) 方法。 Sun 认为不适合包含这样的接口,我不知道为什么。可能他们认为这没有用。您在另一个答案中引用的“GNU Trove”库提供了这样的接口。

或者,您始终可以使用包装器。您可以存储 HistoryItemWrapper 实例,而不是在辅助集中存储 HistoryItem 实例,每个实例都链接到实际的 HistoryItem 并提供 hashCode该集合所需的 ()/equals() 方法。

HashSet is hardcoded to use hashCode() and equals(). You could implement your own HashSet-like class, possibly by ruthlessly duplicating Java's own source code, but that's plain ugly, contradicts any decent set of software development rules, and is possibly illegal with regards to Java's source code license (this depends on the actual JDK, e.g. Sun/Oracle's JDK vs OpenJDK).

You can do things with TreeSet, though. TreeSet normally uses the compareTo() method of the elements, not the hashCode() or equals(). Moreover, a TreeSet instance can be built with a custom Comparator instance, which is then invoked to do comparisons, making you free to have your own rules. A compareTo() method (or a Comparator.compare() method) must implement an order, which may be a bit trickier than a simple hashCode()-and-equals(), but this usually not hard either. TreeSet is sometimes said to be slower than HashSet, but the actual difference is slight and it takes a very specific situation to actually be able to notice that difference in any way.

Conceptually, there could be a hash equivalent of Comparator for HashSet: an interface HasherAndEqualizer with int hashCode(Object obj) and boolean equals(Object obj1, Object obj2) methods. Sun did not see it fit to include such an interface, I do not know why. Possibly they did not think it would be useful. The "GNU Trove" library that you cite in another answer provides such an interface.

Alternatively, you can always use wrappers. Instead of storing HistoryItem instances in your secondary set, you can store HistoryItemWrapper instances, each linking to an actual HistoryItem and providing the hashCode()/equals() methods you need for that set.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文