Sorted copy construction for ArrayList - java

I have an ArrayList.
How can I instantiate a new List with the same data but sorted?
I thought about the following:
Use the ArrayList copy constructor and then use Collections.sort
Use a TreeSet
For option (1) there is the extra overhead of copying the elements and then sorting.
For option (2) duplicates will be removed.
What is the best way for this?

If you can use third-party libraries, then with Guava this is just
List<Foo> sortedCopy = Ordering.from(comparator).sortedCopy(list);
(Disclosure: I contribute to Guava.)

The "best way" depends on your requirements: do you want the duplicates removed? Use a TreeSet; do you want to keep the duplicates? Copy, then sort. Trying to get the fastest one out of the two is premature optimization.

In Java 8 you can use streaming:
ArrayList<Integer> myArrayList = new ArrayList();
myArrayList.add(4);
myArrayList.add(6);
List<Integer> myNewSortedList = myArrayList.stream().sorted().collect(Collectors.asList());
However, the list above must not be mutated. If you want that, you can instead collect as an ArrayList:
myArrayList<Integer> myNewSortedList = myArrayList.stream().sorted().collect(Collectors.toCollection(ArrayList::new));

Don't use a Treeset to get a sorted copy of a List. It'll remove duplicates. (Unless this is what's desired, but then it's a different problem from creating a new sorted copy of a List).
Use option 1 - Create a new List and call Collections.sort() on it, and possibly use your own Comparator if desired.

Related

How to add elements in List when used Arrays.asList()

We cannot perform <Collection>.add or <Collection>.addAll operation on collections we have obtained from Arrays.asList .. only remove operation is permitted.
So What if I come across a scenario where I require to add new Element in List without deleting previous elements in List?. How can I achieve this?
Create a new ArrayList using the constructor:
List<String> list = new ArrayList<String>(Arrays.asList("a", "b"));
One way is to construct a new ArrayList:
List<T> list = new ArrayList<T>(Arrays.asList(...));
Having done that, you can modify list as you please.
Arrays.asList(),generates a list which is actually backed by an array and it is an array which is morphed as a list. You can use it as a list but you can't do certain operations on it such as adding new elements. So the best option is to pass it to a constructor of another list obj like this:
List<T> list = new ArrayList<T>(Arrays.asList(...));
You can get around the intermediate ArrayList with Java8 streams:
Integer[] array = {1, 2, 3};
List<Integer> list = Streams.concat(Arrays.stream(array),
Stream.of(4)).collect(Collectors.toList());
This should be pretty efficient as it can just iterate over the array and also pre-allocate the target list. It may or may not be better for large arrays. As always, if it matters you have to measure.
The Constructor for a Collection, such as the ArrayList, in the following example, will take the array as a list and construct a new instance with the elements of that list.
List<T> list = new ArrayList<T>(Arrays.asList(...));
http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#ArrayList(java.util.Collection)
These days the streams API can easily get you an ArrayList in a concise and functional manner:
Stream.of("str1", "str2").collect(Collectors.toList()));
Of course this also has the flexibility to transform using mappings. For example, while writing unit tests for Spring security code it was convenient to write the following:
Stream.of("ROLE_1", "ROLE_2").map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
The list returned by Collectors.toList is an ArrayList and may be modified as required by your code.
Arrays.asList()
generates an unmodifiable list on object creation. You can use the below code.
List list = Collections.synchronizedList(new ArrayList(...));
This convert allows the list to add and remove objects. I have only tested in java 8.
ArrayList<Object> MyObjectList = new ArrayList<>();
Arrays.asList(params[1]).forEach((item)-> {
MyObjectList.add(item);
});

Java - maintaining order of collection of objects

How would you go about maintaining an order of collection business objects
<BO1, BO2, BO3, BO4>
so that when you remove BO2, amd BO4 you get
<BO1, BO3>
and then when you add BO2
<BO1, BO2, BO3>
You have several ways of doing that but it depends of the type of collection you want to use. Obviously, you don't want to maintain the order of insertions but an order based on the type of elements in the list.
So, before saying use this or that, ask yourself the following question:
Can my collection hold duplicate elements?
1) If YES: then you could use an implementation of a List object (ArrayList, LinkedList, etc). But you will need to sort the list after each insertion:
List<MyObj> list = ...
list.add(myObjInstance);
Collections.sort(list);
To avoid having to sort the list on each insertion you could use the TreeList implementation from Apache Commons Collections.
2) If the answer to the previous question is NO. Then use a TreeSet, you won't need sort the collection on each insertion with that implementation.
Be aware that your object elements have to implement the Comparable interface in order to be sortable.
Unless you use a sorted order, I don't see how the collection is supposed to know that BO2 should go in the middle.
This will do what you want if your Business object implement Comparable
SortedSet<BusObj> bos = new TreeSet<>();
bos.addAll(Arrays.asList(bo1, bo2, bo3, bo4));
bos.removeAll(Arrays.asList(bo2, bo4));
bos.add(bo2);
Make your business object Comparable and use a sorted collection (like TreeSet which is a SortedSet).
Use a SortedSet
http://docs.oracle.com/javase/7/docs/api/java/util/SortedSet.html
There are 2 options: use a List and do the sorting yourself by inserting at the proper location or use a sorted collection.
The sorted collection I think you want is SortedSet http://docs.oracle.com/javase/6/docs/api/java/util/SortedSet.html.
The SortedSet requires entries to implement the Comparable interface.
There is also another question that you should look at: Sorted collection in Java
Aswering my question:
I guess also PriorityQueue would be a solution, if one were not interested in the random access.

How to initialize a dynamic array in java?

If I have a class that needs to return an array of strings of variable dimension (and that dimension could only be determined upon running some method of the class), how do I declare the dynamic array in my class' constructor?
If the question wasn't clear enough,
in php we could simply declare an array of strings as $my_string_array = array();
and add elements to it by $my_string_array[] = "New value";
What is the above code equivalent then in java?
You will want to look into the java.util package, specifically the ArrayList class. It has methods such as .add() .remove() .indexof() .contains() .toArray(), and more.
Plain java arrays (ie String[] strings) cannot be resized dynamically; when you're out of room but you still want to add elements to your array, you need to create a bigger one and copy the existing array into its first n positions.
Fortunately, there are java.util.List implementations that do this work for you. Both java.util.ArrayList and java.util.Vector are implemented using arrays.
But then, do you really care if the strings happen to be stored internally in an array, or do you just need a collection that will let you keep adding items without worrying about running out of room? If the latter, then you can pick any of the several general purpose List implementations out there. Most of the time the choices are:
ArrayList - basic array based implementation, not synchronized
Vector - synchronized, array based implementation
LinkedList - Doubly linked list implementation, faster for inserting items in the middle of a list
Do you expect your list to have duplicate items? If duplicate items should never exist for your use case, then you should prefer a java.util.Set. Sets are guaranteed to not contain duplicate items. A good general-purpose set implementation is java.util.HashSet.
Answer to follow-up question
To access strings using an index similar to $my_string_array["property"], you need to put them in a Map<String, String>, also in the java.util package. A good general-purpose map implementation is HashMap.
Once you've created your map,
Use map.put("key", "string") to add strings
Use map.get("key") to access a string by its key.
Note that java.util.Map cannot contain duplicate keys. If you call put consecutively with the same key, only the value set in the latest call will remain, the earlier ones will be lost. But I'd guess this is also the behavior for PHP associative arrays, so it shouldn't be a surprise.
Create a List instead.
List<String> l = new LinkedList<String>();
l.add("foo");
l.add("bar");
No dynamic array in java, length of array is fixed.
Similar structure is ArrayList, a real array is implemented underlying it.
See the name ArrayList :)

Variable length (Dynamic) Arrays in Java

I was wondering how to initialise an integer array such that it's size and values change through out the execution of my program, any suggestions?
Yes: use ArrayList.
In Java, "normal" arrays are fixed-size. You have to give them a size and can't expand them or contract them. To change the size, you have to make a new array and copy the data you want - which is inefficient and a pain for you.
Fortunately, there are all kinds of built-in classes that implement common data structures, and other useful tools too. You'll want to check the Java 6 API for a full list of them.
One caveat: ArrayList can only hold objects (e.g. Integers), not primitives (e.g. ints). In MOST cases, autoboxing/autounboxing will take care of this for you silently, but you could get some weird behavior depending on what you're doing.
Arrays in Java are of fixed size. What you'd need is an ArrayList, one of a number of extremely valuable Collections available in Java.
Instead of
Integer[] ints = new Integer[x]
you use
List<Integer> ints = new ArrayList<Integer>();
Then to change the list you use ints.add(y) and ints.remove(z) amongst many other handy methods you can find in the appropriate Javadocs.
I strongly recommend studying the Collections classes available in Java as they are very powerful and give you a lot of builtin functionality that Java-newbies tend to try to rewrite themselves unnecessarily.
Arrays are fixed size once instantiated. You can use a List instead.
Autoboxing make a List usable similar to an array, you can put simply int-values into it:
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
I disagree with the previous answers suggesting ArrayList, because ArrayList is not a Dynamic Array but a List backed by an array. The difference is that you cannot do the following:
ArrayList list = new ArrayList(4);
list.put(3,"Test");
It will give you an IndexOutOfBoundsException because there is no element at this position yet even though the backing array would permit such an addition. So you need to use a custom extendable Array implementation like suggested by #randy-lance
It is recommend to use List to deal with small scale size.
If you have a huge number of numbers, NEVER use List and autoboxing,
List< Integer> list
For every single int, a new Integer is auto created. You will find it getting slow when the size of the list increase. These Integers are unnecessary objects.
In this case, to use a estimated size would be better,
int[] array = new int[ESTIMATED_SIZE];
How about using a List instead? For example, ArrayList<integer>
You can't change the size of an array. You can, however, create a new array with the right size and copy the data from the old array to the new.
But your best option is to use IntList from jacarta commons. (here)
It works just like a List but takes less space and is more efficient than that, because it stores int's instead of storing wrapper objects over int's (that's what the Integer class is).

UnsupportedOperationException when trying to remove from the list returned by Array.asList

I am using a List to hold some data obtained by calling Array.asList() method. Then I am trying to remove an element using myList.Remove(int i) method. But while I try to do that I am getting an UnsupportedOperationException. What would be the reason for this? How should I resolve this problem?
Array.asList() wraps an array in the list interface. The list is still backed by the array. Arrays are a fixed size - they don't support adding or removing elements, so the wrapper can't either.
The docs don't make this as clear as they might, but they do say:
Returns a fixed-size list backed by the specified array.
The "fixed-size" bit should be a hint that you can't add or remove elements :)
Although there are other ways around this (other ways to create a new ArrayList from an array) without extra libraries, I'd personally recommend getting hold of the Google Collections Library (or Guava, when it's released). You can then use:
List<Integer> list = Lists.newArrayList(array);
The reason I'm suggesting this is that the GCL is a generally good thing, and well worth using.
As noted in comments, this takes a copy of the array; the list is not backed by the original array, and changes in either collection will not be seen in the other.
It's not java.util.ArrayList. Arrays.asList() returns its own List implementation (with changes "written through" to the array.).
It's a fixed-size list so it does not support removal.
You can create a real ArrayList from it:
new java.util.ArrayList<>(Arrays.asList(someArray));
It's very confusing how asList() works, I must admit.
Please read the API docs for Arrays.asList():
Returns a fixed-size list backed by the specified array. (Changes to the returned list
"write through" to the array.)
Note that Collections.remove(int) is marked in the Javadocs as an "optional operation", meaning not all Collections will support it. "fixed-size list" means you cannot change the list's size, which remove() would do. So it's not supported.
If you want to change the list generated by Arrays.asList(), just copy it, e.g. new ArrayList(Arrays.asList(...)).
The implementation you receive from asList doesn't implement a full List interface. I would transform the list to ArrayList and then do modifications on it.
See remove().
Because you get read-only list.
try
List newList = new ArrayList(myList);
use
ArrayList instead of List
List has fixed size element, List can neither addition item nor remove item

Categories