Why can't I get an item from a HashSet without an enumeration?

I am looking for information about HashSet Design Managers. As far as I know, my question applies to both Java and C # HashSets, making me think that there must be some good reason for this, although I can’t think of myself.

After I inserted an element into a HashSet, why is it impossible to get this element without an enumeration, is it hardly an effective operation? Moreover, the HashSet is clearly built in a way that supports efficient extraction.

It would be useful for me to have Remove (x) and Contains (x) return the actual element that is being removed or contained. This is not necessarily the element that I pass to the Remove (x) or Contains (x) function. Of course, I think that I could achieve the same effect through HashMap, but why spend all this space and effort when it is quite possible to do it with a set?

I can appreciate that there may be some design issues, that adding this feature will allow you to use a HashSet that is not consistent with their role or future role in the structure, but if so, what are these design issues?

Edit

To answer a few more questions, more details:

I use an immutable reference type with overridden hashcode, equals, etc. to emulate the value type in C #. Let say that the type has members A, B and C. Hashcode, equals, etc. It depends only on A and B. Given that some A and BI want to get this equivalent element from hashset and get it C. I won 'I can use a HashSet for this, but I would like to know if there are good reasons for this. Following is the pseudo code:

public sealed class X{ object A; object B; object extra; public int HashCode(){ return A.hashCode() + B.hashCode(); } public bool Equals(X obj){ return obj.A == A && obj.B == B; } } hashset.insert(new X(1,2, extra1)); hashset.contains(new X(1,2)); //returns true, but I can't retrieve extra 
+30
java c # hashset
Sep 29 '09 at 20:41
source share
11 answers

How do you suggest getting an item from a set of hashes? A collection is by definition not ordered in any way and, therefore, there is no index with which to use this object.

Settings, as a concept, are used to check for inclusion, that is, regardless of whether this item is in a hash dataset. If you want to get a value from a data source using a key or index value, I would suggest looking at either Map or a List .

EDIT: Additional answer based on Editing the original question

Soonil, based on your new information, it looks like you might be interested in implementing your data as a Java Enum, something similar to this:

  public enum SoonilsDataType { A, B, C; // Just an example of what possible public static SoonilsDataType getCompositeValue(SoonilsDataType item1, SoonilsDataType item2) { if (item1.equals(A) && item2.equals(B)) { return C; } } } 

Enum automatically inherits values ​​(), which returns a list of all the values ​​in the enum "set", which you can use to test the inclusion in the same way as Set. In addition, since it is a complete class, you can define new static methods to execute complex logic (for example, I tried to reference the example code). The only thing related to Enum is that you cannot add new instances at runtime, which may not be what you want (although if the size of the given data does not grow at runtime, Enum is What would you like).

+9
Sep 29 '09 at 20:57
source share

In .Net, what you are probably looking for is KeyedCollection http://msdn.microsoft.com/en-us/library/ms132438.aspx

You can get around the nastiness of reimplementing this abstract class every time with some β€œcommon” intelligence. (See IKeyedObject`1.)

Note. Any data transfer object that implements IKeyedObject`1 should have an overridden GetHashCode method that simply returns this.Key.GetHashCode (); and the same for equals ...

My base class library usually ends with something like this:

 public class KeyedCollection<TItem> : System.Collections.ObjectModel.KeyedCollection<TItem, TItem> where TItem : class { public KeyedCollection() : base() { } public KeyedCollection(IEqualityComparer<TItem> comparer) : base(comparer) { } protected override TItem GetKeyForItem(TItem item) { return item; } } public class KeyedObjectCollection<TKey, TItem> : System.Collections.ObjectModel.KeyedCollection<TKey, TItem> where TItem : class, IKeyedObject<TKey> where TKey : struct { public KeyedCollection() : base() { } protected override TItem GetKeyForItem(TItem item) { return item.Key; } } ///<summary> /// I almost always implement this explicitly so the only /// classes that have access without some rigmarole /// are generic collections built to be aware that an object /// is keyed. ///</summary> public interface IKeyedObject<TKey> { TKey Key { get; } } 
+10
Jan 26 '11 at 15:56
source share

If you change the object after setting it, its hash may change (this is especially likely if hashCode () has been overridden). If the hash changes, it will not be searched in the set, since you will try to search for an object that hashes in a different place than it is stored.

In addition, you need to make sure that you have redefined hashCode and are equal in your object if you want to look for equal objects that are different instances.

Please note that this is all for Java - I assume that C # has something similar, but since several years have passed since I used C #, I will let others talk to him about the possibilities.

+4
Sep 29 '09 at 20:46
source share

I assume that the designers of the Set interface and the HashSet class wanted to make sure that the remove(Object) method defined in the Collection interface is also applicable to Set ; this method returns a boolean value indicating whether the object was successfully deleted. If designers wanted to provide functionality where remove (Object) would return an β€œequal” object already to Set , this would mean a different signature of the method.

In addition, given that the deleted object is logically equal to the object transferred for deletion (Object), it can argue about the added value when returning the contained object. However, I had this problem before and used the card to solve the problem.

Note that in Java a HashSet uses the HashMap internally, and therefore, instead of using the HashMap there is no additional storage cost.

+3
Sep 29 '09 at 21:01
source share

Why not just use a HashMap<X,X> ? It does exactly what you want. Just do .put(x,x) every time, and then you can just save the saved item to x with .get(x) .

+3
Sep 13 '12 at 22:18
source share

It looks like you're really looking for Map<X,Y> , where Y is type extra1 .




(rant below)

The equals and hashCode methods determine the meaningful uniformity of an object. The HashSet class assumes that if two objects are equal, as defined by Object.equals(Object) , there is no difference between the two objects.

I would say that if object extra makes sense, your design is not perfect.

+1
Sep 30 '09 at 17:54
source share

solvable . The desire to find an element seems to me completely true, because the representative used for the search may differ from the element found. This is especially true if the elements contain information about the keys and values, and the user comparison mapper compares only the key part. See Code Example. The code contains a comparison tool that implements a custom search and captures the found element. This requires an instance of a comparator. Clear the link to the item found. Search using Contains. Access to the item found. Be aware of multi-threaded issues when sharing a comparison instance.

 using System; using System.Collections.Generic; namespace ConsoleApplication1 { class Box { public int Id; public string Name; public Box(int id, string name) { Id = id; Name = name; } } class BoxEq: IEqualityComparer<Box> { public Box Element; public bool Equals(Box element, Box representative) { bool found = element.Id == representative.Id; if (found) { Element = element; } return found; } public int GetHashCode(Box box) { return box.Id.GetHashCode(); } } class Program { static void Main() { var boxEq = new BoxEq(); var hashSet = new HashSet<Box>(boxEq); hashSet.Add(new Box(3, "Element 3")); var box5 = new Box(5, "Element 5"); hashSet.Add(box5); var representative = new Box(5, "Representative 5"); boxEq.Element = null; Console.WriteLine("Contains {0}: {1}", representative.Id, hashSet.Contains(representative)); Console.WriteLine("Found id: {0}, name: {1}", boxEq.Element.Id, boxEq.Element.Name); Console.WriteLine("Press enter"); Console.ReadLine(); } } } // namespace 
+1
Mar 11 '16 at 7:30
source share

Installing objects in these languages ​​was basically designed as a set of values, not for mutable objects. They verify that the objects placed in them are unique with equals. That's why containing and deleting returns a boolean, not an object: they check or delete the value you pass to them.

And in fact, if you do a (X) on the set and expect to get another object Y, this means that X and Y are equal (i.e. X.equals (Y) => true), but somewhat different, which seems wrong.

0
Sep 29 '09 at 20:55
source share

I was given an interesting suggestion on how to use the Map, as my own objects define themselves as KeyValuePairs. Although a good concept, unfortunately, KeyValuePair is not an interface (why not?) And is a structure that removes this plan from the air. In the end, I will refuse my own Set, as my limitations allow me this option.

0
01 Oct '09 at 18:54
source share

Short answer; because objects cannot be immutable.

I ran into a specific problem that you are describing, where the HashCode is based on fixed fields within a member class, but the class contains additional information that can be updated without changing the hash.

My solution was to implement a generic MyHashSet <T> based on ICollection <T> but wrapped around the dictionary <int, List <T β†’ to provide the required search performance, where the int key is HashCode T. However, this shows that if the HashCode of the objects is members can change, then a dictionary search, followed by a comparison of comparisons of items in the list, will never find the changed items. There is no mechanism for forcing members to remain unchanged, so the only solution is to list the party.

0
Mar 14 2018-12-12T00:
source share

After you wonder the same thing, and you can definitely see the source code:

source: http://referencesource.microsoft.com/#System.Core/System/Collections/Generic/HashSet.cs

A collection is a collection of unique elements (objects or values). In a .net implementation, an element matches another element (not unique) if the comparison Equals method returns true for two elements. No, if two elements have the same hash code. therefore, verifying the existence of an element is a two-step process. first using hashset to minimize the number of elements to compile, and then the compression itself.

If you want to receive an element, you should be able to provide a function to obtain a unique identifier. You can know the hash code of the required item. But this is not enough. since more than one item can have the same hash. you will also need to provide the element itself so that you can call the Equal method. and clearly, if you have an item, there is no reason to receive it.

You can create a data structure that requires that none of the two unique elements ever return the same hash code. and how you can get an item from him. it will be faster than adding *, and extraction will be possible if you know the hash. if two elements that are not equal but return the same hash are placed in it, the first one will be overwritten. as far as I know, this type does not exist in .net, and no, it is not the same as a dictionary.

*, given that the GetHash method is the same.

0
Nov 15 '14 at 7:52
source share



All Articles