Create java collection with n clones of an object - java

In Java, is there a one-line way to create a collection that is initialized with n clones of an object?
I'd like the equivalent of this:
foo = vector<vector<int> >(10); c++, creates 10 different empty vectors
[ [] for i in range(10) ] Python, an array of 10 distinct empty arrays
Array.new(10) { [] } Ruby, same as Python
In Java, I've only found
new ArrayList<ArrayList<Integer> >(Collections.nCopies(10, new ArrayList<Integer>()))
However, this is not equivalent to the other examples, because the lists alias.
Is there a way to create an array of distinct object clones, without using a for loop, and preferably without resorting to external libraries?

If you're using Java 8 you could use its streams:
Stream.generate(ArrayList<Integer>::new)
.limit(10).collect(Collectors.toList());
The Stream.generate() method takes a Supplier that knows how to produce a value and generates an infinite stream of those values (each value is obtained by calling the supplier again, so they are all different, unlike Collections.nCopies()). Placing a limit() on the stream and then collecting the results to a list thus yields a list of distinct entries.
Note that starting in Java 16 Stream has a toList() method, so this can become a little cleaner:
Stream.generate(ArrayList<Integer>::new).limit(10).toList();

For those who want to pass in constructor arguments (which is not possible with the accepted answer and suppliers as mentioned here) - you can use the following (I do not know if there is a better solution but it at least fulfilled my needs):
final List<MyObject> result = IntStream.range(0, n)
.mapToObj(index -> new MyObject(...))
.collect(Collectors.toList());
whereas you would replace n by the number of elements you want to fill the list with and MyObject and new MyObject(...) with your type and ctor-call respectively.
This creates a stream of integers ranging from 0 to n (n exclusive), maps every "index" to any object returned by the lambda-expr. in mapToObj and finally converts the stream to a list which will contain n distinct instances of MyObject.

Even with the introduction of Java 8 Supplier, there is unfortunately not a succinct one-liner like nCopies. To be honest, I don't know why. (Though #DavidConrad has shown that Stream can do this.)
You can easily create one yourself, for example:
public static <E, L extends List<? super E>> L fill(
L list, Supplier<E> sup, int n) {
for(; n > 0; --n)
list.add(sup.get());
return list;
}
Call like:
List<List<Integer>> list = ArrayUtils.fill(
new ArrayList<>, ArrayList<Integer>::new, 10
);
For arrays, there is the new method Arrays#setAll:
Integer[] oneToTen = new Integer[10];
Arrays.setAll(oneToTen, i -> i + 1);
List<Integer> asList = Arrays.asList(oneToTen);
But it is a void method so it can't be used in a single statement. (Personal remark: why can't Java API be fluid?)
Prior to Java 8 there is not a library method to do this and it is more cumbersome to create one. Since clone is protected, it cannot be invoked generically. Reflection can do it but reflection is pretty cumbersome.

vector<vector<int> > = new vector<vector<int> >(10);
Is not syntactically correct but lets say you meant vector<vector<int> > foo(10);. You are using the fill constructor which will initialize the container size and then initialize each element to a copy of the value_type parameter (or the default constructor if you didn't specify anything). This will use a loop.
[ [] for i in range(10) ] and Array.new(10) { [] } are just doing the looping on 1 line and copying an empty list type structure in.
As you indicated the nCopies method is not equivalent because the result is immutable and you are not creating copies (or clones). The reference to the same element is used when every index is accessed. See the openjdk copies implementation for reference.
Some of the difficulties with java is there is no guarantee of a default constructor like in C++ and the syntax is a bit different than most scripting languages. This may be a good opportunity to take a second and understand what is going on under the covers to ensure your solution is not doing more work than necessary. Some follow up questions to ask yourself:
What other construct (besides a loop did you have in mind)? I believe there will be a loop at some level.
How do you really want to be initializing the ArrayList objects inside the outer ArrayList? For example what size do you want them to be? Should they be initially populated with anything? How big do you expect them to grow? Do they need to be uniform size or does it makes sense for some to be bigger/smaller? Does it make sense to lazily initialize these lists?
To help answer these questions it may be good practice to write your own generic static initializer for your use case. After you get the simple case down if your use case varies it may make your solution more generic to use the Factory Pattern to initialize your inner lists. As you can see there is a good deal of issues to consider and in the simple case you may just end up with something like:
public static <T> List<List<T>> newListofLists(int outerSize, int innerSize, T value) {
List<List<T>> outer = new ArrayList<List<T>>(outerSize);
for (int i = 0; i < outer.size(); ++i) {
List<T> inner = new ArrayList<T>(innerSize);
outer.add(inner);
for (int j = 0; j < inner.size(); ++j) {
inner.add(value);
}
}
return outer;
}
This can then be used to initialize your lists in one line like:
List<List<Integer>> myList = newListofLists(10, 5, -1);

Related

Instantiating array of objects with streams

I have an array of ints that I want to use to instantiate a array or list of objects. In my case, the old-fashoned way to do it would be:
int[] layer_sizes = {784, 500, 10};
Layer[] layers = new Layer[layer_sizes.length];
for (int i=0; i<layer_sizes.length; i++)
layers[i] = new Layer(layer_sizes[i]);
But now I see Java 8 has all these fancy streams. I now want to do something like Python's list comprehensions:
List<Layer> layers = Stream.of(layer_sizes).map(size -> Layer(size));
But it doesn't let me do that, and I'm not sure why... The message it gives is
incompatible types: no instance(s) of type variable(s) R exist so that Stream<R> comforms to List<Layer> where R, T are type variables....
Is there a way to use Streams to construct an array of objects in one line?
EDIT: Not a duplicate of previous question, because it turns out that there're some peculiarities of making streams from primitives.
Conclusion
Thank you Sam Sun and Eran. The line I ended up using was this:
Layer[] layers = Arrays.stream(layer_sizes).boxed().map(Layer::new).toArray(Layer[]::new);
Whatever boxed() is, you need it, unless you declare layer_sizes as an Integer instead of int.
P.S. If the java developers are reading this, it would be amazing for Java 9 or whatever's next to have something like
Layer[] layers = {new Layer(size) for (size:layer_sizes)} // OR at least:
Layer[] layers = Stream.of(layer_sizes).map(Layer::new).toArray()
You are missing two things - collecting the Stream into a List and invoking the Layer constructor (you are missing the new keyword) :
List<Layer> layers =
IntStream.of(layer_sizes)
.mapToObj(size -> new Layer(size))
.collect(Collectors.toList());
And if you wish your output to be an array instead of a List, call toArray instead of collect.
EDIT :
I just realized that Stream.of, when passed an int[], would produce a Stream<int[]>, not a Stream<Integer>. Therefore, you should use IntStream, which handles primitive int elements.
The alternative is to replace the input int[] layer_sizes = {784, 500, 10}; with Integer[] layer_sizes = {784, 500, 10};.
Eran's answer has the general idea of what to do, but is missing a few key details.
Using Stream.of on an int[] will result in a Stream<int[]>; one of the magical artifacts of Java.
Instead, you should use Arrays.stream or IntStream.of to get a IntStream (remember, primitives can't be a parameter).
For the map operation, you can use a method reference to Layer::new.
This all boils down to this new snippit
List<Layer> layers = IntStream.of(layer_sizes).boxed().map(Layer::new).collect(Collectors.toList());

Fixed number of generic objects which can be iterated over

I have a class which always holds four objects:
class Foo<E> {
Cow<E> a, b, c, d;
}
I want to be able to iterate over them, so ideally I'd like to use an array:
class Foo<E> {
Cow<E>[] cows = new Cow<E>[4]; // won't work, can't create generic array
}
I don't want to use a list or a set since I want there to always be 4 Cow objects. What's the best solution for me?
If you want to preserve the genericity, you will have to reimplement something similar to a list and I don't think it is worth it.
You said:
The first is that you can add and remove elements to and from a list.
Well you can create an unmodifiable list:
List<E> list = Collections.unmodifiableList(Arrays.asList(a, b, c, d));
The second is that I'm creating a quadtree data structure and using a list wouldn't be too good for performance. Quadtrees have a lot of quadrants and using lists would decrease performance significantly.
First you can initialise the list to the right size:
List<E> list = new ArrayList<>(4);
Once you have done that, the list will only use a little bit more memory than an array (probably 8 bytes: 4 byte for the backing array reference and another 4 byte for the size).
And in terms of performance an ArrayList performs almost as good as an array.
Bottom line: I would start by using a list and measure the performance. If it is not good enough AND it is due to using a list instead of an array, then you will have to adapt your design - but I doubt that this will be your main issue.
Use a generic ArrayList and simply have methods to insert values into your object, and do checks inside those methods, to make sure you don't end up having more than 4 Cow objects.
I will suggest creating a bounded list. Java does not have an inbuilt one however you can create a custom one using Google collections or use the one in Apache collections. See Is there a bounded non-blocking Collection in Java?
Use Collection instead of array:
List<Cow<E>> cows = new ArrayList<>(); // in Java 7
Or
List<Cow<E>> cows = new ArrayList<Cow<E>>(); //Java 6 and below
More information will show why it is IMPOSSIBLE to have arrays whit generics. You can see here
Cow<E>[] cows = (Cow<E>[])new Cow[4];
or
Cow<E>[] cows = (Cow<E>[])new Cow<?>[4];

What's more efficient and compact: A huge set of linkedlist variables or a two-dimensional arraylist containing each of these?

I want to create a large matrix (n by n) where each element corresponds to a LinkedList (of certain objects).
I can either
Create the n*n individual linked lists and name them with the help of eval() within a loop that iterates through both dimensions (or something similar), so that in the end I'll have LinkedList_1_1, LinkedList_1_2 etc. Each one has a unique variable name. Basically, skipping the matrix altogether.
Create an ArrayList of ArrayLists and then push into each element a linked list.
Please recommend me a method if I want to conserve time & space, and ease-of-access in my later code, when I want to reference individual LinkedLists. Ease-of-acess will be poor with Method 1, as I'll have to use eval whenever I want to access a particular linked list.
My gut-feeling tells me Method 2 is the best approach, but how exactly do I form my initializations?
As you know the sizes to start with, why don't you just use an array? Unfortunately Java generics prevents the array element itself from being a concrete generic type, but you can use a wildcard:
LinkedList<?>[][] lists = new LinkedList<?>[n][n];
Or slightly more efficient in memory, just a single array:
LinkedList<?>[] lists = new LinkedList<?>[n * n];
// Then for access...
lists[y * n + x] = ...;
Then you'd need to cast on each access - using #SuppressWarnings given that you know it will always work (assuming you encapsulate it appropriately). I'd put that in a single place:
#SuppressWarnings("unchecked")
private LinkedList<Foo> getList(int x, int y) {
if (lists[y][x] == null) {
lists[y][x] = new LinkedList<Foo>();
}
// Cast won't actually have any effect at execution time. It's
// just to tell the compiler we know what we're doing.
return (LinkedList<Foo>) lists[y][x];
}
Of course in both cases you'd then need to populate the arrays with empty linked lists if you needed to. (If several of the linked lists never end up having any nodes, you may wish to consider only populating them lazily.)
I would certainly not generate a class with hundreds of variables. It would make programmatic access to the lists very painful, and basically be a bad idea in any number of ways.

ArrayList initialization equivalent to array initialization [duplicate]

This question already has answers here:
Create ArrayList from array
(42 answers)
Initialization of an ArrayList in one line
(34 answers)
Closed 6 years ago.
I am aware that you can initialize an array during instantiation as follows:
String[] names = new String[] {"Ryan", "Julie", "Bob"};
Is there a way to do the same thing with an ArrayList? Or must I add the contents individually with array.add()?
Arrays.asList can help here:
new ArrayList<Integer>(Arrays.asList(1,2,3,5,8,13,21));
Yes.
new ArrayList<String>(){{
add("A");
add("B");
}}
What this is actually doing is creating a class derived from ArrayList<String> (the outer set of braces do this) and then declare a static initialiser (the inner set of braces). This is actually an inner class of the containing class, and so it'll have an implicit this pointer. Not a problem unless you want to serialise it, or you're expecting the outer class to be garbage collected.
I understand that Java 7 will provide additional language constructs to do precisely what you want.
EDIT: recent Java versions provide more usable functions for creating such collections, and are worth investigating over the above (provided at a time prior to these versions)
Here is the closest you can get:
ArrayList<String> list = new ArrayList(Arrays.asList("Ryan", "Julie", "Bob"));
You can go even simpler with:
List<String> list = Arrays.asList("Ryan", "Julie", "Bob")
Looking at the source for Arrays.asList, it constructs an ArrayList, but by default is cast to List. So you could do this (but not reliably for new JDKs):
ArrayList<String> list = (ArrayList<String>)Arrays.asList("Ryan", "Julie", "Bob")
Arrays.asList("Ryan", "Julie", "Bob");
Well, in Java there's no literal syntax for lists, so you have to do .add().
If you have a lot of elements, it's a bit verbose, but you could either:
use Groovy or something like that
use Arrays.asList(array)
2 would look something like:
String[] elements = new String[] {"Ryan", "Julie", "Bob"};
List list = new ArrayList(Arrays.asList(elements));
This results in some unnecessary object creation though.
The selected answer is: ArrayList<Integer>(Arrays.asList(1,2,3,5,8,13,21));
However, its important to understand the selected answer internally copies the elements several times before creating the final array, and that there is a way to reduce some of that redundancy.
Lets start by understanding what is going on:
First, the elements are copied into the Arrays.ArrayList<T> created by the static factory Arrays.asList(T...).
This does not the produce the same class as java.lang.ArrayListdespite having the same simple class name. It does not implement methods like remove(int) despite having a List interface. If you call those methods it will throw an UnspportedMethodException. But if all you need is a fixed-sized list, you can stop here.
Next the Arrays.ArrayList<T> constructed in #1 gets passed to the constructor ArrayList<>(Collection<T>) where the collection.toArray() method is called to clone it.
public ArrayList(Collection<? extends E> collection) {
......
Object[] a = collection.toArray();
}
Next the constructor decides whether to adopt the cloned array, or copy it again to remove the subclass type. Since Arrays.asList(T...) internally uses an array of type T, the very same one we passed as the parameter, the constructor always rejects using the clone unless T is a pure Object. (E.g. String, Integer, etc all get copied again, because they extend Object).
if (a.getClass() != Object[].class) {
//Arrays.asList(T...) is always true here
//when T subclasses object
Object[] newArray = new Object[a.length];
System.arraycopy(a, 0, newArray, 0, a.length);
a = newArray;
}
array = a;
size = a.length;
Thus, our data was copied 3x just to explicitly initialize the ArrayList. We could get it down to 2x if we force Arrays.AsList(T...) to construct an Object[] array, so that ArrayList can later adopt it, which can be done as follows:
(List<Integer>)(List<?>) new ArrayList<>(Arrays.asList((Object) 1, 2 ,3, 4, 5));
Or maybe just adding the elements after creation might still be the most efficient.
How about this one.
ArrayList<String> names = new ArrayList<String>();
Collections.addAll(names, "Ryan", "Julie", "Bob");
This is how it is done using the fluent interface of the op4j Java library (1.1. was released Dec '10) :-
List<String> names = Op.onListFor("Ryan", "Julie", "Bob").get();
It's a very cool library that saves you a tonne of time.

Java: Are there some tools out there which are able to refactor X[][] to List<List<X>>?

I have to refactor an existing project, which is not that small. It contains a lot of arrays declarations and accesses:
(X is not a generic type, it's just a placeholder).
declarations: X[] and X[][],
access: someArray[i] and someArray[i][j].
I have to rewrite everything to use generic Lists:
declaration: List<X> and List<List<X>>,
access: someList.get(i) and someList.get(i).get(j).
I couldn't find a possibility to automatize such refactoring, neither in Eclipse, nor in Netbeans (both newest versions).
Are there some tools available to do such refactoring?
EDIT:
The project is very algorithm-oriented. Internal implementation of algorithms will not be touched. But the exposure to the external world must be changed. Most classes are made in such a way, that they only hold some result arrays or arrays of arrays.
exposure to the external world must be changed
In that case I'd avise not to change it everywhere, but to :
change only return types of the public methods
write an utility method, which looks like:
public static List<List<X>> asList(X[][] x) {
List<X[]> list = Arrays.asList(x);
List<List<X>> newList = new ArrayList<List<X>>(list.size());
for (X[] xArray : list) {
newList.add(Arrays.asList(xArray));
}
return list;
}
use that method to change the only result of each public method. I.e.
public List<List<X>> someAlgorithm(...) {
// algorithm code
X[][] result = ...;
return Utils.asList(result); // add only this line
}
I can hardly agree that things you are going to do could be called 'refactoring'.
Arrays has some possibilities that lists don't have (and of course vise versa).
For example, if you create new array of 10 integer elements then its size is 10, and it has ten zero values.
You can also use its index in some tricky way. For example, think about radix sort algorithm. To implement it with lists you should first add a lot of zeros to this list and you'll get twice worse performance.
I'm telling this to explain the idea that it's almost impossible to implement robust tool for doing what you want to do.

Categories

Resources