Sorted view of a List - java

is it somehow possible to get a sorted List view of a List with the elements from the original List, modify the elements, for example set a property, but the original List should reflect the changes?
Background is I'm sorting two Lists, then for each equal element I'm setting a property (basically it's the intersection) but finally I need the unsorted List with the modified elements.
kind regards,
Johannes

Probably the simplest thing to do is add the elements to a new list, sort that list, and when you modify the elements, the original elements will still be modified...
List<?> origA;
List<?> origB;
List<?> newA = new ArrayList<?>(origA);
List<?> newB = new ArrayList<?>(origB);
Collections.sort(newA);
Collections.sort(newB);
// do mods

If the List holds references to objects (not primitive data types), then just copy the list, sort it and modify the elements.

Does it have to be a list? If you keep your elements in a TreeSet, they will always be sorted as you iterate through them, even after you add/remove the elements. Remember though that modifying an element already in the TreeSet may break the sort order. You can remove and add the element to the TreeSet to get around that.
If you have to use a list, you can use Collections.sort(List list) after adding or modifying an element. Of course, if you have to call it often, there will be a performance hit. If performance is a concern, you can just insert the new element (or move the modified one) to maintain the sorted order, which will be cheaper than sorting it: O(n) vs O(n*log(n))

Related

Java - Data structure design - Fixed size, random access, thread safe, sorted collection

So, in some question I was required to implement the following:
Data structure of fixed size (n=10), that is always ordered (descending, not that it matters), thread safe, and supports random access.
My solution was - using a TreeSet, whenever adding an element, if there are already n elements, remove the smallest element (if the new element if bigger than it) and add the new element. Otherwise, just add the new element.
When accessing a random index, use the TreeSet iterator to iterate until the required index.
I don't like this solution so much. So I thought of another solution:
Using an ArrayList, constructed with the size of n. Whenever trying to add an element, do a Collections.binarySearch() for the element and insert it if it doesn't exists, using the index returned from binarySearch. If after adding the element the list length is bigger than n (equals n+1 actually), remove the smallest element (which is on the end of the list). This way, we get log(n) for add (same as TreeSet from previous solution) and random access is O(1). Only thing I don't like about it is that the add() for an arbitrary index in the middle of the list requires shifting all the elements after it. (works well for small n but for big n maybe not?)
For both solutions I use ReentrantReadWriteLock - acquire writeLock() for add and readLock() for the get() / read operations.
Is there a better solution?
**
Collections.synchronizedList(List i) makes the passed argument a threadsafe List.
you can implement the comparable interface when creating your class and override compareTo() method in a way that it orders the element by descending order when you are adding them to the ArrayList<>() or you can go for Comparator class and overriding compare() method while sorting it.
In the total collection, only List(I) supports RandomAccess.
ArrayList<Employee> arrayList = Collections.synchronizedCollection(new ArrayList<Employee>(10));
and if you want the same item should not be added to the ArrayList use Comparator and return 0 when a new item (want to add) and last item (already added) is equal. handle the return value in such a manner that if (...==0){ don't add to the data ) else { add it }.
I hope I could give u some hint.

How can I add elements from one ordered integer ArrayList to another integer ordered ArrayList?

The task is to add elements from one ordered integer ArrayList to another and the elements in the result array should be in order too. It should work in the most effective way.
My Logic is this:
A.addAll(B);
Collections.sort(A);
But I'm not really sure this is the best solution.
From the documentation for ArrayList.addAll()
Appends all of the elements in the specified collection to the end of
this list, in the order that they are returned by the specified
collection's Iterator.
My takeaway from this is that sorting the result array after adding your elements makes no sense, as the elements from your original array will appear in the same order in the result array as they originally were in.

ArrayList, LinkedList and Vector which one is the best for adding or removing the element from the list

I appeared for an interview where interviewer asked me about ArrayList, Linked list and Vector. His question was
ArrayList, LinkedList, and Vector are all implementations of the List interface. Which of them is most efficient for adding and removing elements from the list ? And I was supposed to answer including any other alternatives I may be aware of.
I answered him but he seems little not impressed by my answer.
Can someone tell me more about this ?
Thank you
LinkedList is implemented as a double linked list. It's performance on add and remove is better than Arraylist, but worse on get and set methods.You will have to traverse the list up to a certain point in those cases. So, definitely not LinkedList.
ArrayList is implemented as a resizable array. As more elements are added to ArrayList, its size is increased dynamically. It's elements can be accessed directly by using the get and set methods, since ArrayList is essentially an array.
Vector is similar with ArrayList, but it is synchronised.
ArrayList is a better choice if your program is thread-safe. Vector and ArrayList require more space as more elements are added. Vector each time doubles its array size, while ArrayList grow 50% of its size each time.
LinkedList, however, also implements Queue interface which adds more methods than ArrayList and Vector, such as offer(), peek(), poll(), etc.
A lot is dependent on what kind of requirement you are working on. A decision can be taken depending upon needs.
LinkedList is best suited for adding/removing items, reason being you just change the links between the items without manipulating other unrelated items to accomplish current operation. This also makes linked lists comparatively faster than other containers.
Cheers!
Choose LinkedList if you have a lot of data to adding and removing from list but be careful if you wish to get element from your list than this will be not right Data Structure.
List<T> list = new LinkedList<T>();
LinkedList is implemented using Double linked List,since its perrformance is good at adding/removing elements from/to list.
Performance of ArrayList vs. LinkedList :
The time complexity comparison is as follows:
get() : O(n)
add() : O(1)
remove() : O(1)

Java - Difference between fixed-sized list and list with initial capacity specified

I am having an issue in understanding this.
while we do
List<Integer> list = Arrays.asList(array);
we can not use methods like add, remove on that list. I know that Arrays.asList() returns a fixed-sized list.
What I don't understand is if we create a list with initial capacity specified like
List<Integer> list2 = new ArrayList<Integer>(10);
we can perform all the operations on that list. What is the difference between fixed-sized list and list with initial capacity specified?
I have read many answers on this but having such a hard time understanding this. Can anyone explain?
Thanks.
Arrays.asList(array) returns an object of type java.util.Arrays.ArrayList, which does not support add and remove operations.
While the code below will return an object of type java.util.ArrayList, which supports add and remove operations.
List<Integer> list2 = new ArrayList<Integer>(10);`
Very simply, Arrays.asList is so you can use List methods with an array. ArrayList(int) is for when you need to create a really large ArrayList and want to help speed things up a bit.
In more detail: the List returned by asList is intended as a wrapper to an array. Since you cannot resize an array, the methods that change the size of a List are unimplemented. Most of the time I just use asList to add a fixed number of elements to a collection simply. eg.
new ArrayList<String>(Arrays.asList("hello", "world"));
Confusingly, the implementation of ArrayList is very similar -- it's a List backed by an array. However, ArrayList allows you to change it's size. To do this it keeps a separate fields about the how many objects are in the list and the length of the backing array. Add an element and the ArrayList just sets array[size] to the element and then increments the size field. But what if array[size] is out of bounds? At this point the ArrayList creates a new, larger array and copies over the elements from the previous backing array. However, if you are creating a large List then this constant creation of new backing arrays can start to take up a lot of time. As such, if you know the approximate number of elements that will be in the List you can use this to inform the ArrayList about the size of the initial backing array it should create. This is what the ArrayList(int) constructor is for. Only in exceptional circumstances will you need to worry about giving the ArrayList a length hint.

Collection with no duplicates and in random order in Java

It looks like I can't either use an ArrayList nor a Set:
Set<> - I can avoid duplicates using a set, but no shuffle option // Collections.shuffle(List<?> list)
ArrayList<> - I can use shuffle to randomise the list, but duplicates are allowed.
I could use a Set and convert this into an ArrayList (or the other way around) to avoid the duplicates. Alternatively, loop through the set to randomise the items. But I am looking for something more efficient.
You can maintain two separate collections, an ArrayList and a HashSet, and reject insertion of any item which is present in the HashSet.
If you are concerned with encapsulation, wrap the two collections in a meta-object that implements List, and carefully document that insertions of duplicate elements will be rejected, even if the general contract of List doesn't prescribe so.
Talking about the cost of this solution, I believe that in terms of time the cost would be absolutely negligible if compared to a plain ArrayList: most operations on HashSets cost amortized O(1), namely lookup and insertion. On the other hand, your memory usage will be twice (or more, depending on the HashSet load factor).
As far as I know sets aren't ordered, so you obviously cannot shuffle items of sets. For removing duplicates from a list I found this: How do I remove repeated elements from ArrayList?.
With the least amount of code and most elegance you can do something like:
public void testFoo() {
Set<Integer> s = new TreeSet<Integer>();
s.add(2);
s.add(1);
s.add(3);
Collections.shuffle(Arrays.asList(s.toArray()));
}
But this is not very effective, you could use an array and a hash function to put the elements in the desired spot on the array, and check of they are already there before putting them, this will work in O(n) time, so it's very good, but needs a little more code and some attention to the hash function.
You can use a Map to avoid duplicates and then Map.entrySet() and shuffle the ArrayList
You could actually use an "ordered set", e.g. TreeSet. In order to get a random order, don't insert the actual item but a wrapper with some random weight and use a corresponding comparator. Re-shuffling however would require to update all wrapper weights.

Categories