Array List retrieval order - java

I have a java ArrayList to which I add 5 objects.
If I iterate over the list and print them out, then iterate over the list and print them out again.
Will the retrieval order in these 2 cases be the same? (I know it may be different from the insertion order)

Yes, assuming you haven't modified the list in-between. From http://docs.oracle.com/javase/6/docs/api/java/util/List.html:
iterator
Iterator<E> iterator()
Returns an iterator over the elements in this list in proper sequence.
A bit vague, perhaps, but in other portions of that page, this term is defined:
proper sequence (from first to last element)

(I know it may be different from the insertion order)
No it won't. The contract of List requires that the add order is the same as the iteration order, since add inserts at the end, and iterator produces an iterator that iterates from start to end in order.
Set doesn't require this, so you may be confusing the contract of Set and List regarding iteration order.
From the Javadoc:
Iterator<E> iterator()
Returns an iterator over the elements in this list in proper sequence.

It's in the specification of the List interface to preserve order.
It's the Set classes that don't preserve order.

If you're not mutating the list, then the iteration order will stay the same. Lists have a contractually specified ordering, and the iterator specification guarantees that it iterates over elements in that order.

Yes, an ArrayList guarantees iteration order over its elements - that is, they will come out in the same order you inserted them, provided that you don't make any insertions while iterating over the ArrayList.

Retrieval does not vary unless you change the iterator you are using. As long as you are using the same method for retrieval and have not changed the list itself then the items will be returned in the same order.

When you add an element to an ArrayList using add(E e), the element is appended to the end of the list. Consequently, if all you do is call the single-argument add method a number of times and then iterate, the iteration will be in exactly the same order as the calls to add.

The iteration order will be the same everytime you iterate over the same unmodified list.
Also, assuming you add the elements using the add() method, the iteration order will be the same as the insertion order since this method appends elements to the end of the list.

Yes the retrieval order is guaranteed to be the same as long as list is not mutated and you use the same iterator, but having to need to rely on retrieval order indicated something fishy with the design. It is generally not a good idea to base business logic upon certain retrieval order.

Even Sets will return the same result, if you don't modify them (adding or removing items to them).

Related

Create a List of unique values in java

I have data of which the sequence is as important as its unique elements. Meaning if something has already been added it should not be added again and the sequence must be remembered.
Set does not remember the sequence in which it was added (either hash or sort), and List is not unique.
What is the best solution to this problem?
Should one have a list and loop through it to test for uniqueness - which I'm trying to avoid?
Or should one have two collections, one a List and one a Set - which I'm also trying to avoid?
Or is there a different solution to this problem altogether.
In the bellow code was your reference
LinkedHashSet<String> al=new LinkedHashSet<String>();
al.add("guru");
al.add("karthik");
al.add("raja");
al.add("karthik");
Iterator<String> itr=al.iterator();
while(itr.hasNext()){
System.out.println(itr.next());
}
output
guru
karthik
raja
Use LinkedHashSet. It serves as both a List and a Set. It has the uniqueness quality of a set but still remembers the order in which you inserted items to it which allows you to iterate it by order of insertion.
From the Docs:
Hash table and linked list implementation of the Set interface, with predictable iteration order. This implementation differs from HashSet in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is the order in which elements were inserted into the set (insertion-order). Note that insertion order is not affected if an element is re-inserted into the set. (An element e is reinserted into a set s if s.add(e) is invoked when s.contains(e) would return true immediately prior to the invocation.)
You can use SortedSet
or LinkedHashSet
LinkedHashSet is the best possible way out

a collection data structure to keep items sorted

I got a program which is using an ArrayList<T> and that type T also implements Comparable<T>. I need to keep that list sorted.
For now, when I insert a new item, I add it to the ArrayList and then invoke Collections.sort(myArrayList).
Is sorting with Collections.sort every time I insert a new item seriously hurt run time complexity?
Is there a better suited data structure I can use to always keep the list sorted? I know of a structure called a PriorityQueue but I also need to be able to get the list's elements by index.
EDIT:
In my specific case, inserting a new item happens much less than geting an already existing item, so eventually a good advice could also be to stay with the ArrayList since it got a constant time complexity of getting an item. But if you know of anything else...
It seems like Collection.Sort is actually the way to go here since when the collection is already almost sorted, the sorting will take not longer than O(n) in the worst case.
Instead of using Collections.sort(myArrayList) after every insertion you might want to do something a bit smarter as you know that every time you insert an element your collection is already ordered.
Collections.sort(myArrayList) takes 0(nlogn) time, you could do an ordered insert in an ordered collection in O(n) time using Collections.binarySearch. If the collection is ordered in ascending order Collections.binarySearch returns the index of the element you are looking for if it exists or (-(insertion point) - 1). Before inserting an element you can look for it with Collections.binarySearch (O(logn) time). Done that you can derive the index at which inserting the new element. You can then add the element with addAt in O(n) time. The whole insertion complexity is bounded by the addAt so you can do an ordered insert in an ArrayList in O(n) time.
List is an ordered collection, which means you need to have the ability to access with index. If a collection internally shuffles or sorts the elements, the insertion order wont be same as the order of the elements in the internal data structure. So you cannot depend on index based access anymore. Hence Sun didn't provide a SortedList or a TreeList class. That is why you use Collections.sort(..)
Apache commons-collections does provide a TreeList class but it is not a sorted List and is called so because it uses a tree data structure to store the elements internally. Check its documentation here - http://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/list/TreeList.html
A single data structure cannot provide both sorting and index based retrieval. If the input set is limited to a few hundreds or thousands, you can keep two data structures in parallel.
For example, ArrayList for index based retrieval and TreeMap (or priority queue) for sorting.

Why set <Integer> is sorting added values?

When I start to add value into Set<Integer> I get sorting elements.
Please refer to this example:
Set<Integer> generated = new HashSet<Integer>();
generated.add(2);
generated.add(1);
generated.add(0);
Here I get sorting Set [0, 1, 2]. I would like to get value as I add to generated object.
A HashSet does not have a predictable order for elements. Use a LinkedHashSet to preserve insertion order of elements in a set:
Hash table and linked list implementation of the Set interface, with predictable iteration order.
Set<Integer> generated = new LinkedHashSet<Integer>();
generated.add(2);
generated.add(1);
generated.add(0);
Firstly it's just a co-incidence that you get sorted value first time. If you run that code multiple time, you'll see the output in some random order. That's because a HashSet doesn't enforce any ordering on elements you add.
Now to get the elements in the order you inserted, you can use LinkedHashSet, that maintains the insertion order.
The HashSet does not guarantee the order of the elements. From the JavaDoc:
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.
So, in order to keep guarantee the order a LinkedHashSet can be used. From the JavaDoc:
Hash table and linked list implementation of the Set interface, with predictable iteration order.
This linked list defines the iteration ordering, which is the order in which elements were inserted into the set (insertion-order).
Simply instantiate your Set like this:
Set<Integer> generated = new LinkedHashSet<>();
First, regarding the title of your question, Set<Integer> is only the declaration type and its not responsible of any sorting / unsorting behavior, the main reason for using the Set interface is when caring about uniqueness — it doesn't allow duplicates, additional informations from Javadocs:
A Set is a Collection that cannot contain duplicate elements.
Second, it's pure concidence that you got sorted set, use HashSet when you don't care about order when iterating through it, more infos from javadocs:
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. This class permits the null element.
Third, regarding what you are looking for:
I would like to get value as I add to generated object.
then you need to use LinkedHashSet which takes care of the order in which elements were inserted, again from javadocs:
This linked list defines the iteration ordering, which is the order in
which elements were inserted into the set (insertion-order). Note that
insertion order is not affected if an element is re-inserted into the
set
you may use it simply like this:
Set<Integer> generated = new LinkedHashSet<Integer>();
Fourth and Last, as additional information, another important collection that you need to be aware of it, is the TreeSetwhich guarantees that the elements will be sorted in ascending order, according to natural order, javadocs:
The elements are ordered using their natural ordering, or by a
Comparator provided at set creation time, depending on which
constructor is used

Will getting the first item from the iterator of a set return a random value?

I'm using Set#iterator().next(); all by itself, and I'm wondering if:
A) Will that cause memory leaks, or at least any kind of avoidable overhead,
and
B) Whether or not item it returns will be a random item, and if I use this method multiple times, it'll give a different item every time?
Iterator<E> iterator()
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).
http://docs.oracle.com/javase/7/docs/api/java/util/Set.html#iterator()
If you need to get the elements in the same order every time you iterate through the Set, try one of these specific implementations that guarantee order:
TreeSet: sorts elements based on their value (natural order)
ConcurrentSkipListSet: sorts elements based on their value (natural order)
LinkedHashSet: sorts elements based on the order they were inserted in the set (insertion order)
The first two implement the SortedSet interface.
From the docs of Iterator#next()
Returns the next element in the iteration.
Which means that it'll return the items in the order they are stored in the Set. And regarding the different item, Yes, it'll return next(different) item always(till there are more items remaining in the Set) and will terminate(by throwing the NoSuchElementException) once it has exhausted all of them.

java data structure that retains order, does not allow duplicates, and allows removal and insertion other than by object

Is there a java data structure that:
does not allow duplicates
retains insertion order
allows removal and insertion at either the start or end of the collection
There is LinkedHashSet, but it only allows remove(object), add(object) as per sets.
LinkedHashSet will allow removal of the first element, just do
Iterator iter = linkedHashSet.iterator();
if(iter.next()) {
iter.remove();
}
If you're willing to give up a little performance for no duplicates, you can always extend ArrayDeque and override all the methods that insert into the collection to see if the element already exists.

Categories

Resources