Java: Retrieving an element from a HashSet
Why cannot I retrieve an element from a HashSet? Consider my HashSet containing a list of MyHashObjects with their hashCode() and equals() methods overridden correctly. I was hoping to construct a MyHashObject myself, and set the relevant hash code properties to certain values. I can query the HashSet to see if there «equivalent» objects in the set using the contains() method. So even though contains() returns true for the two objects, they may not be == true. How come then there isn’t any get() method similar to how the contains() works? What is the thinking behind this API decision?
10 Answers 10
If you know what element you want to retrieve, then you already have the element. The only question for a Set to answer, given an element, is whether it contains() it or not.
If you want to iterator over the elements, just use a Set.iterator() .
It sounds like what you’re trying to do is designate a canonical element for an equivalence class of elements. You can use a Map to do this. See this Stack Overflow question or this one for a discussion.
If you are really determined to find an element that .equals() your original element with the constraint that you must use the HashSet , I think you’re stuck with iterating over it and checking equals() yourself. The API doesn’t let you grab something by its hash code. So you could do:
MyObject findIfPresent(MyObject source, HashSet set) < if (set.contains(source)) < for (MyObject obj : set) < if (obj.equals(source)) return obj; >> return null; >
It is brute-force and O(n) ugly, but if that’s what you need to do.
how to find and return objects in java hashset
According to the HashSet javadoc, HashSet.contains only returns a boolean. How can I «find» an object in a hashSet and modify it (it’s not a primitive data type)? I see that HashTable has a get() method, but I would prefer to use the set.
thanks everyone! My object actually contains a linked list i need to update frequently, so i think i’m going to just go with HashTable rather than do an expensive iteration for every object update.
6 Answers 6
You can remove an element and add a different one.
Modifying an object while it is in a hash set is a recipe for disaster (if the modification changes the hash value or equality behavior).
This is not totally true. It’s safe to modify a HashSet element if the change doesn’t impact the object’s equality (and hash code). For example, if equals and hashCode were not overridden, then the change is safe to do as its equality is not changed.
To quote the source of the stock Sun java.util.HashSet:
public class HashSet extends AbstractSet implements Set, Cloneable, java.io.Serializable < static final long serialVersionUID = -5024744406713321676L; private transient HashMapmap;
So you are paying for a map, you might as well use it.
You can iterate through the set to find your object.
A word of warning from the API doc though:
"Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set."
Java - how to get element from HashSet?
Tehya-Blanchard
1. Overview
In java Set / HashSet / LinkedHashSet don't have get method.
Ofcourse it is possible to 'GET' element from Set in java, we just need to think a bit different when using this data structure. What I mean by this?
When we want to GET element from Set in java we just need to check if Set contains the object we want to get. So we already have our element we want to get from HashSet, the only think left to do is to check if Set have this object inside by using contains method with correctly implemented hashCode() and equals() .
HashSet internally uses HashMap and contains method on HashSet calls HashMap containsKey method.
Internally HashSet uses HashMap which looks like this:
private transient HashMap map;
We can go inside JDK and check it by ourselves.
The best way to understand what I mean is by analyzing below 2 examples.
When we use intellij IDEA we can just click on contains method and attach the debugger inside.
2. Example 1 - HashSet with String
This example uses String, String have internal hashCode and equals implemented in JDK.
import java.util.HashSet; import java.util.Set; public class JavaGetElementFromHashSetExample1 < public static void main(String[] args) < Setset = new HashSet<>(); set.add("A"); set.add("B"); set.add("C"); // get A // we already have String "A" // so we just only need to check if "A" exists in HashSet System.out.println(set.contains("A")); // true // get D System.out.println(set.contains("D")); // false > >
String - Internal hashCode and equals implemented in JDK.
public int hashCode() < int h = hash; if (h == 0 && value.length >0) < char val[] = value; for (int i = 0; i < value.length; i++) < h = 31 * h + val[i]; >hash = h; > return h; > public boolean equals(Object anObject) < if (this == anObject) < return true; >if (anObject instanceof String) < String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) < char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) < if (v1[i] != v2[i]) return false; i++; >return true; > > return false; >
HashSet - contains JDK implementation (as we can see HashSet internally uses HashMap)
package java.util; public class HashSet extends AbstractSet implements Set, Cloneable, java.io.Serializable < // . private transient HashMapmap; // . public boolean contains(Object o) < return map.containsKey(o); >// . >
3. Example 2 - HashSet with custom User objects
In this example we implement explicit hashCode and equals for User class.
When we invoke contains method
import java.util.HashSet; import java.util.Objects; import java.util.Set; public class JavaGetElementFromHashSetExample2 < public static void main(String[] args) < Setset = new HashSet<>(); set.add(new User(1L, "A")); set.add(new User(2L, "B")); set.add(new User(3L, "C")); // get 1st user by checking if set contains our User object // User class implement custom hash code and equals method // we use key User(1L, "A") to 'get' user from Set // we already have this object so we just only need to check if // object is in our hash set System.out.println(set.contains(new User(1L, "A"))); // true // get 4th user System.out.println(set.contains(new User(4L, "D"))); // false > private static class User < private long userId; private String username; public User() < >public User(long userId, String username) < this.userId = userId; this.username = username; >public long getUserId() < return userId; >public void setUserId(long userId) < this.userId = userId; >public String getUsername() < return username; >public void setUsername(String username) < this.username = username; >@Override public boolean equals(Object o) < if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return userId == user.userId && Objects.equals(username, user.username); >@Override public int hashCode() < return Objects.hash(userId, username); >@Override public String toString() < return "User'; > > >
Как получить элемент в Set?
если в Set хранится строка "Tim", и ты хочешь получить строку "Tim" - какой смысл в Set? даже если бы была возможность сделать set.get("Tim") ?
а если не я создаю set мне просто его нужно использовать, достать значение - так что поможет только конвертировать его в List или другую коллекцию ?
@mtb, если я правильно понял вы хотите проверить наличие элемента в коллекции (если это так измените вопрос), для этого можно воспользоваться методом contains.
"а если элементном в Set является объект" ну тогда нужно указать объект в вопросе и по какому полю объекта вы будете находить нужный.
3 ответа 3
hset.stream().filter(data -> Objects.equals(data, "Tim")).findFirst().get()
Тоже столкнулся с этим вопросом. Я так понял, что до появления Stream API можно было написать метод для поиска этого эемента, который использовал бы итератор.
@Олексій Моренець, зачем? Куда проще -> делаем перебор элементов коллекции циклом -> в цикле выставляем условие на соответствие искомогу элемента -> return element;
cats.removeIf(elem -> elem.name.equals("Васька"));
Удаляет объект Cat с полем name == "Васька" из Set cats
Думаю, это примерно то что было нужно автору вопроса. Я написал такое:
а IDEA предложила сократить. Вообще полезно смотреть что она предлагает 🙂
В HashSet - нельзя получить элемент по ключу.
HashSet инкапсулирует HashMap. Вы лишь можете проверить наличие элемента в коллекции.
Если же все таки вам нужно получить элемент, тогда вы должны вызывать iterator() или используйте for() (под капотом он использует Iterator). Если сразу вы решили, что вам нужно будет получать данные по ключу, то HashSet не подойдет вам как структура для хранения ваших элементов, во первых она не предназначена для этого, а во вторых сложность времени поиска элемента занимает O(n).