How can Iterator can using in set(java)? - java

my question was why does iterator work on set?
Here is my example code,
public class Staticex {
public static void main(String[] args) {
HashSet set = new HashSet();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
set.add(5);
Iterator iter = set.iterator();
while (iter.hasNext()) {
System.out.println(iter.next());
}
}
}
I understand, set is unordered, In contrast List
So, How can get the values ​​one by one through an iterator?
Is iterator changing set into like list which ordered data structure?

How can Iterator can using in set?
Like you are using it.
How can get the values ​​one by one through an iterator?
Your code is doing that.
Is iterator changing set into like list which ordered data structure?
No.
The thing that you are missing is what "unordered" means. It means that the order in which the (set's) elements are returned is not predictable1, and not specified in the javadocs. However each element will be returned once and (since the elements of a set are unique!) only once for the iteration.
1 - Actually, this is not strictly true. If you have enough information about the element class, the element values, how they were created and how / when they were added to the HashSet, AND you analyze the specific HashSet implementation ... it is possible that you CAN predict what the iteration order is going to be. For example if you create a HashSet<Integer> and add 1, 2, 3, 4, ... to it, you will see a clear (and repeatable) pattern when you iterate the elements. This is in part due to the way that Integer.hashCode() is specified.

Referring to the documentation, we see that:
Iterator<E> iterator()
Returns an iterator over the elements in this collection. There are no guarantees concerning the order in which the elements are returned (unless this collection is an instance of some class that provides a guarantee).
Since there are no guarantees concerning the order in which the elements are returned for iterator, it is not a problem for iterator to apply to Set, which is unordered.
Further, it is not changing the Set into a List

Set is unordered in a logical sense. When you have a bag of things, there isn't a sense of order when they are inside the bag. But when you take each thing out of the bag, one at a time, you end up with some order. And like the other answer has mentioned, you cannot rely on that order since it is purely accidental.

I understand, set is unordered, In contrast List
This is not necessarily true. SortedSet is a subinterface of Set. As the name implies, instances of this interface are ordered in some fashion. For example, TreeSets are ordered using their natural ordering, or by a Comparator provided at set creation time, depending on which constructor is used. Also, the main distinction between Set and List is that List allows for duplicate objects to be contained, whereas Set does not.
Now, if you are talking specifically about HashSet, then you are correct about being unordered.
I think your confusion is because you are asking yourself "why is the print out showing the numbers in numeric (insertion) order?" This is sort of a complicated answer for someone of your familiarization level, but the order in which they are printed out is because you are inserting integers and their hash code are basically their numeric values. And, although there is no guarantee as to the order in which the elements of the hash set are returned when iterating, the implementation of HashSet is backed by a hash table. In fact, if you change the insertion order of those same values, most likely the numbers will be printed out in the same numeric order. Now, remember that with all that, the order is not guaranteed. This may not be true, for instance, if you change the set elements to be String objects.

Related

Retrieval of data in HashSet

I want to know that in which manner, the data is retrieve in HashSet
I have inserted data in different order and output data is in another order.
Can someone please tell the logic behind this?
Code is like this :-
class Test
{
public static void main(String[]args)
{
HashSet<String> h = new HashSet<String>();
// Adding elements into HashSet using add()
h.add("India");
h.add("Australia");
h.add("South Africa");
System.out.println(h);
}
}
Output:- [South Africa, Australia, India]
From Javadoc of HashSet
It makes no guarantees as to the
iteration order of the set; in particular, it does not guarantee that the
order will remain constant over time.
HashSet works same as HashMap with Value. Moreover It internally uses HashMap With value constant Object called "PRESENT". By doing this HashSet guarantee uniqueness but not order It locate the set elements similarly as what Hashmap do.
You can see the implementation of HashSet on internet.
As said, the ordering of elements in a HashSet is not guaranteed to be anything, nor to be constant over time.
This is due to the nature of the underlying data structure.
In your case, it looks like the Strings were stored in a LIFO queue, but another implementation of HashSet may well do things differently (and even this one might as more items get inserted, start to behave differently).
As per the above, please see the Javadoc for HashSets - the order is not guaranteed. https://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html
Use the LinkedHashSet if you want it to maintain the order of elements.

Order of elements in a set in java

If i create 2 lists from the same set, can I be sure that I get the same ordering in both the lists? (I do not care about the ordering as long as both the lists have the same order and I am not performing any operations on the sets between creating the two lists.)
List l = new ArrayList(set);
List l1 = new ArrayList(set);
I understand that there are guaranteed ways of creating these lists and getting the same order and that there isn't a good reason for me to create two lists this way, but I would like to know why the ordering of elements in a set would change if no modify operations are performed on it.
Edit: The set is an unordered HashSet
You will propably get the same ordering in the lists l and l1. But since most Sets are unordered, you have no guarantee that there will be the same order.
Technically you could write an implementation of the Set interface which changes its order everytime any method is called. This would still fulfil the interface.
Since in the constructor new ArrayList(Collection) the toArray method of the collection is called, we can have a look at the Javadoc of Set#toArray():
Returns an array containing all of the elements in this set. If this set makes any guarantees as to what order its elements are returned by its iterator, this method must return the elements in the same order.
While the Javadoc of Set#iterator() says there is no general guarantee:
Returns an iterator over the elements in this set. The elements are returned in no particular order (unless this set is an instance of some class that provides a guarantee).
Given this, I would strongly advise you not to rely on the ordering of the lists.
As per documentation
public ArrayList(Collection c) Constructs a list
containing the elements of the specified collection, in the order they
are returned by the collection's iterator
So it really depends on the Set interface implementation class, if the order is constant.
For example, if you use LinkedHashSet the iteration order is predictable.
There are structures that their orders are guaranteed or not. If we mention of Set interface implemented by Java, there is no guarantee. Most likely the constructor of ArrayList make uses of iterator of Set. So both list certainly contain always same elements but order. That's actually why Set uses contains keyword instead of find to check an element whether it exists.
It's sub-interface, SortedSet, represents a set that is sorted
according to some criterion. In Java 6, there are two standard
containers that implement SortedSet. They are TreeSet and
ConcurrentSkipListSet.
In addition to the SortedSet interface, there is also the
LinkedHashSet class. It remembers the order in which the
elements were inserted into the set, and returns its elements in that
order.
One way to impose a desired (natural, or otherwise) order on an unordered collection like a Set is to create an ordered Set (in other words, a SortedSet) from the given set. If your sets are not too large and all you care for is a predictable iteration order, you can do:
// set = ...
List<? extends Comparable> list = new TreeSet<>(set).stream().collect(Collectors.toList());
This assumes that the set consists of elements that are comparable. Alternatively, you could use your own comparator in the TreeSet constructor. There may be some issues in creating such a comparator however, if the elements themselves are not comparable.
There are some intertesting and good answers here, I can propose a solution.
List list = new ArrayList(set);
List secondList = new ArrayList(list);

How does a Set determine the order of its values?

I wrote a simple program that takes an array of strings that get converted into a list, then into a Set, which is finally printed.
Here is the code:
public static void main(String[] args) {
String[] array = {"hello", "goodbye", "welcome", "thanks"};
List<String> list = Arrays.asList(array);
System.out.println(list);
Set<String> set = new HashSet<String>(list);
System.out.println(set);
}
The set returns
[hello, goodbye, welcome, thanks]
[hello, thanks, goodbye, welcome]
And no matter what order I make the array it returns the Set in that particular order. So how does Set<> determine in what order the values should be put into?
The order of the elements in a Set is determined by the order of the elements in its Iterator and, as specified in Set.iterator()
The elements are returned in no particular order (unless this set is an instance of some class that provides a guarantee).
So there is no inherent order to a Set.
However, Set is only an interface. There are various implementstions of a Set that do provide a guarantee.
There's a HashSet - which doesn't - i.e. it optimises itself to achieve O(1) at the expense of a predictable order.
There's a TreeSet - which maintains the natural order of the objects - i.e. "ab" < "ac" and 1 < 10 or any order you define using a Comparator.
There's an EnumSet - which orders by the enum ordinal order - kind of like TreeSet.
There's a LinkedHashSet - which orders in the order the items were added.
There are other more obscure implementations of Set that also have their own character.
The iteration order of a HashSet is an implementation detail that may change from release to release. You should assume that the ordering is magic, inscrutable, and subject to change.
(In practice, it's affected by the hash codes of the elements, the smearing function HashSet uses internally, and the order the hash buckets appear generally.)

How to test if a Java iterator always uses the same order (reproducible ordering)?

I have a code in which for-each-loops on a Set need to rely on the fact that the iterator returns the elements always in the same order, e.g.
for(ParameterObject parameter : parameters) {
/* ... */
}
The iterators returned by HashSet are not guaranteed to have this property, however it is documented that the iterators of LinkedHashSet do have this property. So my code uses a LinkedHashSet and everything works fine.
However, I am wondering if I could endow the my code with a check that the set passed to it conforms to the requirement. It appears as if this is not possible (except of a direct test on LinkedHashSet). There is no interface implemented by LinkedHashSet which I could test on and there is no interface implemented by LinkedHashSet.iterator() which I could test on. It would be nice if there is an interface like OrderConsistentCollection or OrderConsistentIterator.
(I need this property here).
There isn't a way you can check for it -- but you can ensure it anyway, by simply copying the set into a collection that does have that property. A LinkedHashSet would do the trick, but if all you need is the iteration, an ArrayList would probably serve you better.
List<Foo> parameters = new ArrayList<>(parametersSet);
Now parameters will always return an iterator with the same ordering.
That said, you'd probably be fine with Evgeniy Dorofeev's suggestion, which points out that even the sets that don't guarantee a particular ordering usually do have a stable ordering (even if they don't guarantee it). HashSet acts that way, for instance. You'd actually have to have a pretty funky set, or take active randomization measures, to not have a stable ordering.
HashSet's ordering is not guaranteed, but it depends on the hash codes of its elements as well as the order in which they were inserted; they don't want to guarantee anything because they don't want to lock themselves into any one strategy, and even this loose of a contract would make for essentially random order if the objects' hash codes came from Object.hashCode(). Rather than specifying an ordering with complex implications, and then saying it's subject to change, they just said there's no guarantees. But those are the two factors for ordering, and if the set isn't being modified, then those two factors are going to be stable from one iteration to the next.
'HashSet.iterator does not return in any particular order' means that the elements returned by iterator are not sorted or ordered like in List or LinkedHashSet. But the HashSet.iterator will always return the elements in one and the same order while the HashSet is the same.
HashSet iterator is actually predictable, see this
HashSet set = new HashSet();
set.add(9);
set.add(2);
set.add(5);
set.add(1);
System.out.println(set);
I can foretell the output, it will be 1, 2, 5, 9. Because the elements kind of sorted by hashCode.

does java sortedhashset type collection exist?

Does such a thing exist anywhere? Basically I see java has LinkedHashSet but no type of navigatable hash set?
By its very nature, a hash-based data structure is not ordered. You can write wrappers which supplement it with an additional data structure (this is more or less what LinkedHashMap does). But while it makes some sense to keep a hash set and a list, in order to keep a good ordering, you would need a tree or similar data structure. But the tree can work as a set by itself, so you would essentially be duplicating the information (more than in the case of set plus list, which differ more than two different set implemnentations). So the best solution is to just use TreeSet or another SortedSet if you need order.
It's not a HashSet, but as a descendant of Set you have the TreeSet
This class implements the Set interface, backed by a TreeMap instance. This class guarantees that the sorted set will be in ascending element order
You can traverse the elements using the iterator
public Iterator iterator()
Returns an iterator over the elements in this set. The elements are returned in ascending order
You can use a TreeSet but all the operations in it are lg(n)
You can use a LinkedHashSet, which keeps a linked list on top of hashset, but it only maintains insertion ordering (first inserted will be first element in iterator), you cannot have natural or custom ordering
You could also use TreeSet+HashSet approach but two reference for each element will be kept and while add and remove would still be lg(n) the contains will become expected o(n)
choose wisely :)
I guess there's TreeMap which is...related but definitely not the same :)

Categories