Instantiating array of objects with streams - java

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());

Related

JAVA: ImmutableSet as List

I currently get returned an ImmutableSet from a function call (getFeatures()) and due to the structure of the rest of my code to be executed later on- it would be much easier to change this to a List. I have tried to cast it which produces a runtime exception. I have also looked around for a function call to convert it to a list to no avail. Is there a way to do this? My most recent [failed] attempt is shown below:
ImmutableSet<FeatureWrapper> wrappersSet = getFeatures();
List<FeatureWrapper> wrappers = (List<FeatureWrapper>) wrappersSet;
I have found wrapperSet.asList() which will give me an ImmutableList however i would much rather prefer a mutable list
You can't cast a Set<T> into a List<T>. They are entirely-different objects. Just use this copy constructor which creates a new list out of a collection:
List<FeatureWrapper> wrappers = new ArrayList<>(wrappersSet);
ImmutableCollection has the "asList" function...
ImmutableList<FeatureWrapper> wrappersSet = getFeatures().asList();
Bonus points that the returned type an ImmutableList.
If you really wanted a mutable List though, then Vivin's answer is what you want.
Since Guava-21 supports java-8 you can use stream and collector to convert an ImmutableSet to a List:
ImmutableSet<Integer> intSet = ImmutableSet.of(1,2,3,4,5);
// using java-8 Collectors.toList()
List<Integer> integerList = intSet.stream().collect(Collectors.toList());
System.out.println(integerList); // [1,2,3,4,5]
integerList.removeIf(x -> x % 2 == 0);
System.out.println(integerList); // [1,3,5] It is a list, we can add
// and remove elements
We can use ImmutableList#toImmutableList with collectors to convert an ImmutableList to a ImmutableList :
// using ImmutableList#toImmutableList()
ImmutableList<Integer> ints = intSet.stream().collect(
ImmutableList.toImmutableList()
);
System.out.println(ints); // [1,2,3,4,5]
And the easiest way is to call ImmutableSet#asList
// using ImmutableSet#asList
ImmutableList<Integer> ints = intSet.asList();

Create java collection with n clones of an object

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);

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: how can I create a dynamic array without forcing the type of the values?

I need to create a dynamic array in Java, but the values type differ from String to Int to float. how can I create a dynamic list that I don't need to give it in advanced the type of the values?
The keys just need to be ascending numbers (1,2,3,4 or 0,1,2,3,4)
I checked ArrayList but it seems that I have to give it a fixed type for the values.
thanks!
You can have an array or an ArrayList of Objects which will allow you to contain String, int, and float elements.
You can use this:
List<Object> myList = new ArrayList<Object>();
Integer i = 1;
Double d = 1.2;
String s = "Hello World";
myList.add(i);
myList.add(d);
myList.add(s);
It's pretty rare, in my experience, to want a List<Object>. I think it might be a design smell, and I'd examine the design to see if another set of structures might better represent your data. Without knowing anything about what you're trying to solve, it's hard to say with any confidence, but typically one wants to do things with what one has put into a list, and to do anything meaningful with things once they're just Object, you'll need to examine their type and get reflective, to kind of break away from language basics. Versus storing them in more type-sensitive structures, where you can deal directly with them in their original types without reflection magic.
It's more trouble than it's worth, but it is possible to interact with arrays reflectively.
import java.lang.reflect.Array;
// ...
Object arr = Array.newInstance(int.class, 10);
System.out.println(arr.getClass().getName()); // prints "[I"
System.out.println(Array.getLength(arr)); // prints "10"
Array.set(arr, 5, 42);
if (arr instanceof int[]) {
int[] nums = (int[]) arr;
System.out.println(nums[5]); // prints "42"
}
References
java.lang.reflect.Array API
Do note that in the API you pass arrays as Object. This is because Object is the superclass of all array types, be it int[].class or String[][].class. This also means that there is little compile time safety (as is true with reflection in general). Array.getLength("mamamia") compiles just fine; it'll throw an IllegalArgumentException at runtime.

Should Java treat arrays as objects?

I have often thought it would be a good idea to allow the use of arrays as proper objects with their own methods instead of relying on helper classes like Arrays, Arrays and ArrayUtils.
For example:
ints.sort(); // Arrays.sort(ints);
int[] onemore = ints.add(8); // int[] onemore = ArrayUtils.add(ints, 8);
I am sure I am not the first with this idea but I have had trouble searching for others who have written about this before. Can anyone help me with some references on this topic?
Is this thought to be a good or bad idea, and why?
How easy would this be to implement?
Some other examples might include (but don't get hung up on them, they're extraneous to the question itself):
int[] ints = {5,4,3,2,1};
// Arrays.sort (ints);
ints.sort();
// int pos = Arrays.asList(ints).indexOf (5);
// int pos = ArraysUtils.indexOf (ints, 5);
int pos = ints.indexOf (5);
// Arrays.reverse (ints);
ints.reverse();
Array<Integer> array = ints; // cast to super class.
// int length = Array.getLength (array);
int length = array.getLength();
// Object n = Array.get (array, 3);
Object n = array.get (3);
// Array.set (array, 3, 7);
array.set (3, 7);
Object obj = array;
// if (obj instanceof int[])
// System.out.println(Array.toString((int[]) obj));
// else if (....)
System.out.println (obj);
Arrays are not classes in Java for a good reason - they map well onto people's understanding of how an array should work from experience with C-style languages. There are also performance reasons for making arrays low-level containers rather than objects. Because of this, sometimes there are performance benefits to using a primitive array rather than a Collection.
If you want to use objects, you should just use a Collection (an ArrayList is an example of a collection). It can be clunky, but Collections provide the type of nice methodological access that you seem to want.
Those methods start to look an awful lot like ruby or python idioms. Unfortunately you don't get to do that in java (wish you could).
For one, as others have pointed out, the collections classes do it for you. For another, myarray.sort() isn't so nice because you can create arrays of objects for which sorting has not been defined. Suppose I have
Foo[] foos;
And Foo is not Comparable. What happens on foos.sort()? We definitely wouldn't want to have it only work for primitives
int[] ints;
ints.sort(); //legal
Object[] objects;
objects.sort(); //illegal
and you certainly couldn't have the compiler only allow the syntax for comparable objects. And once you get to something like
myarray.add(new Foo());
it's sort of pointless, as arrays in java aren't growable.
It would be nice if printing out an array didn't give you that useless
([I'm an array(*&(*
rubbish, though.
Yes. But I'm of the opinion that Java should not have any primitives at all. I think primitives in Java are a break from the cleanness of the language. Everything in Java should be objects. Whether or not the objects are allocated on the stack or the heap should be an implementation detail of the JVM not a language construct. But I think my opinion might be more radical than most.
Before autoboxing, dealing with primitives and objects was very cumbersome.
If arrays were objects and could be autoboxed (and generisized!), we could have something like
Array<Integer> myArray = new Integer[];
myArray.add(8);
int x = myArray[0];
....
or
Array<Class<? extends MyBaseObject>> myArray = {ExtendedObject.class}
ExtendedObject object = myArray[0].newInstance();
....
Yes, I believe that arrays should have an API defined beyond the one specified in the language itself. In particular, it's annoying that a Foo[] doesn't implement Iterable<Foo>. Yes, I know it's easy to wrap it - but it's annoying that you have to.
.NET gets this mostly right, with the Array type which is mostly for non-generic access, and various generic interfaces which are deemed to be implemented by the actual arrays. For instance:
IList<int> intList = new int[10];
(It helps that .NET generics cope with primitive types better than Java does.)
The only downsides I've seen of this approach is that arrays can be covariant in .NET, but normal generics aren't, and that things get slightly confusing with non-zero-based arrays and rectangular arrays.
As an aside, various people have referred to arrays as primitives in this thread. While they certainly have special handling, they're not defined to be primitives. From the language spec, section 4.2:
A primitive type is predefined by the Java programming language and named by its
reserved keyword (ยง3.9):
PrimitiveType:
NumericType
boolean
NumericType:
IntegralType
FloatingPointType
IntegralType: one of
byte short int long char
FloatingPointType: one of
float double
Before I answer for SHOULD, I will tell you the state of this issue.
In Java, arrays are considered objects -- you can store them in a List for example. However they are special objects in that they inherit from Object but are not instantiated or accessed with the same syntax (thanks for the correction Peter). They are aggressively optimized by the JVM for obvious performance issues, and thus the way an array is stored is dependent on implementation.
So the Sun argument would be that, if they gave an object API for the array, it could require certain hardware, software, or other specification features to be in place.
The only real interface for arrays are the System.arrayCopy static method or the Array.* static methods, which will most efficiently copy to/from arrays.
In response to SHOULD; it has been solved, although a standard would be better than the answer: use ArrayList.
It is not a BAD idea. Thing is it has already been done on Collections. Try extending ArrayList if you wanna go crazy.
I believe this is very hard to implement without breaking compatibility at many levels.
JVM treats arrays little differently than other objects. Creation/initialization is different: no constructor is called for one thing. How would you want to add new methods? If by adding superclass, would you call its constructor?
Arrays know type of element in runtime, generics don't. If you wanted to add new superclass for all arrays (like you suggested in original question), would you make it generic? Also keep in mind that arrays are covariant in Java, generics aren't.
Arrays have fixed set of methods/fields specified in Java Language Specification (all methods from Objects, which are explicitely named in JLS, length field). Adding new members is likely to break existing clients depending on this. (i.e. arrays are not your random class)
Array serialization would probably be affected too
I am sure there are more implementation details which would make this extremly hard :-(
Programs compiled to work with new methods would not work on older JVMs. What's worse, depending on implementation, programs compiled for old JVMs may not work with modified arrays on new JVMs.
I would like to have methods directly in "Array class", I don't think it's possible to implement it now.
I personally like the idea of everything being an object, and this has already been done in smalltalk, for instance. However, the consequences of making everything, even methods/funcitons an object are very far-reaching (have a look at smalltalk to see what I mean). Being consistent in the application of the "everything is an object"-rule results in a language that doesn't look anything like C (or Java) anymore.
Java was very consciously designed to be approachable to C programmers, and it has succeeded at that, but it's not actually very object oriented compared to smalltalk. It's heritage as a C variant shows up all over the place, like in arrays and the fact that there are primitives.
So to answer the question of SHOULD, I would say no, because Java wouldn't be Java anymore with that change. As others have pointed out, there are other classes that let you handle tasks which might have been done with an array in C using objects in Java, but to get rid of primitive data types and arrays alltogether is a task better left to a different language, IMHO.
For those who missed a previous post which was closed. Some other examples include
int[] ints = {5,4,3,2,1};
ints.sort(); // instead of Arrays.sort(ints);
int pos = ints.indexOf(5); // instead of Arrays.asList(ints).indexOf(5); or ArraysUtils.indexOf(ints, 5);
ints.reverse(); // instead of Arrays.reverse(ints);
Array<Integer> array = ints; // cast to super class.
int length = array.getLength(); // instead of Array.getLength(array);
Object n = array.get(3); // instead of Array.get(array, 3);
array.set(3, 7); // instead of Array.set(array, 3, 7);
Object obj = array;
System.out.println(obj); // prints [5,4,7,2,1] instead of having to
// if (obj instanceof int[]) System.out.println(Array.toString((int[]) obj)); else if (....)
int[] ints2 = ints.copyOf(2);
int[] ints3 = ints.subArray(2,4);
ints.sort(myComparator);
List<Integer> list = ints.asList();
Set<Integer> set = ints.asSet();
long total = ints.sum();
double avg = int.average();
int max = ints.max();
int max2 = ints.max(myComparator);
http://commons.apache.org/lang/api/org/apache/commons/lang/ArrayUtils.html
int[] onemore = ints.add(8); // instead of ArrayUtils.add(ints, 8);
int[] moreInts = ints.addAll(ints2); // instead of ArraysUtils.addAll(ints, ints2);
int[] oneless = int.remove(3); // instead of ArrayUtils.remove(ints, 3);
Integer[] integers = int.toObject();
int[] intsAgain = integers.toPrimitive();
One reason I believe it would be not so hard is that you can add methods indirectly by modifying Object (A real hack I agree, but it shows it works)
By adding methods to Object, the following code
int[] ints = {5, 4, 3, 2, 1};
System.out.println("ints= "+ints);
ints.sort();
System.out.println("after sort() ints= "+ints);
ints = ints.add(6);
System.out.println("after add(6) ints= "+ints);
Prints
ints= [5, 4, 3, 2, 1]
after sort() ints= [1, 2, 3, 4, 5]
after add(6) ints= [1, 2, 3, 4, 5, 6]
This works with Java 5 & 6 and both the compiler and IDE handled this as I expected.

Categories

Resources