Java:从HashSet中检索元素

希望有人能解释为什么我无法从HashSet检索元素。

考虑我的HashSet包含一个MyHashObjects列表,其hashCode()equals()方法被正确覆盖。

我希望做的是自己构建一个MyHashObject ,并将相关的哈希码属性设置为某些值。 我可以使用contains()方法查询HashSet以查看集合中是否存在“等效”对象。 因此,即使contains()为2个对象返回true,它们也可能不是== true。

那么为什么没有类似于contains() get()方法呢?

有兴趣了解这个API决定背后的想法

如果您知道要检索的元素,那么您已经拥有了该元素。 给定一个元素, Set回答的唯一问题是它是否contains()

如果要对元素进行迭代,只需使用Set.iterator()

听起来你正在尝试做的是为元素的等价类指定一个规范元素。 您可以使用Map来执行此操作。 请参阅此SO问题或此 问题进行讨论。

如果你真的决心找到一个元素.equals()你的原始元素,你必须使用HashSet的约束,我认为你一直在迭代它并自己检查equals() 。 API不允许您通过其哈希代码获取内容。 所以你可以这样做:

 MyObject findIfPresent(MyObject source, HashSet set) { if (set.contains(source)) { for (MyObject obj : set) { if (obj.equals(source)) return obj; } } return null; } 

蛮力和O(n)丑陋,但如果这是你需要做的……

听起来你实际上是在尝试将哈希码用作地图中的一个键(这就是HashSets在幕后所做的事情)。 您可以通过声明HashMap来显式地执行此操作。

HashSets没有get ,因为通常您将get方法作为参数提供的对象与您将获得的对象相同。

您可以使用HashMap而不是HashSet

在“重建” MyHashObject上调用ContainsKey()将首先hashCode()检查集合,如果重复哈希码被命中,最后equals()你的“重建”与原始,你可以使用原来检索原始get()

这是O(1),但缺点是你可能必须覆盖equals()hashCode()方法。

如果您知道Set中元素的顺序,则可以通过将Set转换为Array来检索它们。 像这样的东西:

 Set mySet = MyStorageObject.getMyStringSet(); Object[] myArr = mySet.toArray(); String value1 = myArr[0].toString(); String value2 = myArr[1].toString(); 

如果我在我的应用程序中确实知道该对象没有用于搜索任何列表或散列数据结构,并且除了在添加时间接在哈希数据结构中使用的方法之外,不使用equals方法。 是否可以在equals方法中更新set中的现有对象。 请参阅以下代码。 如果我将这个bean添加到HashSet,我可以在key(id)上的匹配对象上进行组聚合。 通过这种方式,我能够实现聚合函数,例如sum,max,min,…. 如果不可取,​​请随时与我分享您的想法。

 public class MyBean { String id; String name; double amountSpent; @Override public int hashCode() { return id.hashCode(); } @Override public boolean equals(Object obj) { if(obj!=null && obj instanceof MyBean ) { MyBean tmpObj = (MyBean) obj; if(tmpObj.id!=null && tmpObj.id.equals(this.id)) { tmpObj.amountSpent += this.amountSpent; retuen true; } } return false; } } 

您需要获取Set对象中包含的对象的想法很常见。 它可以通过两种方式存档:

  1. 根据需要使用HashSet,然后:

     public Object getObjectReference(HashSet set, Xobject obj) { if (set.contains(obj)) { for (Xobject o : set) { if (obj.equals(o)) return o; } } return null; } 

要使这种方法起作用,您需要覆盖hashCode()和equals(Object o)方法。在最坏的情况下,我们有O(n)

  1. 第二种方法是使用TreeSet

     public Object getObjectReference(TreeSet set, Xobject obj) { if (set.contains(obj)) { return set.floor(obj); } return null; } 

这种方法给出了O(log(n)),效率更高。 您不需要为此方法重写hashCode,但您必须实现Comparable接口。 (定义函数compareTo(Object o))。

如果可以使用List作为数据结构来存储数据,而不是使用Map将结果存储在Map的值中,则可以使用以下代码段并将结果存储在同一对象中。

这是一个Node类:

 private class Node { public int row, col, distance; public Node(int row, int col, int distance) { this.row = row; this.col = col; this.distance = distance; } public boolean equals(Object o) { return (o instanceof Node && row == ((Node) o).row && col == ((Node) o).col); } } 

如果将结果存储在距离变量中并且基于坐标检查列表中的项目,则只要您只需要存储一个元素,就可以使用以下内容在lastIndexOf方法的帮助下更改新距离对于每个数据:

  List nodeList; nodeList = new ArrayList<>(Arrays.asList(new Node(1, 2, 1), new Node(3, 4, 5))); Node tempNode = new Node(1, 2, 10); if(nodeList.contains(tempNode)) nodeList.get(nodeList.lastIndexOf(tempNode)).distance += tempNode.distance; 

它基本上是重新实现Set其项目可以被访问和更改。

首先将您的设置转换为Array。 然后,通过数组的索引获取项目。

 Set uniqueItem = new HashSet() ; uniqueItem.add("0"); uniqueItem.add("1"); uniqueItem.add("0"); Object[] arrayItem = mySet.toArray(); for(int i = 0; i < uniqueItem.size();i++){ System.out.println("Item "+i+" "+arrayItem[i].toString()); }