Convert Collection to int[] array - java

There are two existing methods named getDetails(...). One expects a minimum of one mandatory parameter and the other expects a collection (doesn't validate the content/size of the collection).
The problem is that the collection is sometimes passed as empty and according to my business case, I always expect a minimum of one value, to be passed. So, I need to make that method private, which accepts Collections.
// There are two params, to make sure that at-least one is passed by the caller
public static CustomerContext getDetails(int id, int... ids) {
Collection<Integer> idCollection = Instream.of(ids).boxed().collect(Collectors.toSet());
if(!idCollection.contains(id)){
idCollection.add(id);
}
return getDetails(idCollection);
}
I'm planning to make the below method scope to private so that the callers would not call this method with Zero attributes.
public static CustomerContext getDetails(Collection<Integer> idCollection) {
return getDetails(idCollection,false);
}
One of the caller methods is passing Collection object to getDetails like below,
CustomerContext.getDetails(id.getDetails().values());
The id.getDetails() is as below,
public Map<Id,Integer> getDetails(){
return Collections.unmodifiableMap(details);
}
I'm looking for a way to convert the collection id.getDetails().values() into int[] for passing to getDetails(int id,int... ids) instead of calling getDetails(Collection<Integer> idCollection).
I could cast the collection to Integer[] as below,
(Integer[])id.getDetails().values().toArray()
I did not find a way to cast Collection to int[].
Any suggestions would be of great help.
I already referred to some of the existing questions but did not succeed to solve my issue:
Conversion of collection to int array
Convert java.util.Collections to Integer array

Collection to Integer[]
When you need to get a result of type Integer[], you have to provide a function as an argument while calling toArray(), there's no need to apply casting (if you're not passing a parameter toArray() returns an array Object[]).
Integer[] arr = id.getDetails().values().toArray(Integer[]::new);
Collection to int[]
There's no way convert a Collection of Integer type or an array Integer[] into an array int[] directly. It's not possible to obtain one from another simply by doing casting, these types are not compatible.
You have to iterate over the source and populate the newly created int[] array. It can be done either "manually" using a loop, or in a more convenient way with streams, the overall approach doesn't change.
That's how it can be done using Stream API:
int[] arr = id.getDetails().values().stream() // Stream<Integer> - stream of objects
.mapToInt(Integer::intValue) // IntStream - stream of primitives
.toArray();

You can't cast Collection<Integer> to int[], but you can create the array:
int[] values = id.getDetails().values().stream()
.mapToInt(n -> n)
.toArray();
An aside... this code:
if (!idCollection.contains(id)) {
idCollection.add(id);
}
May be changed to just:
idCollection.add(id);
because idCollection is a Set and that's how sets work. It matters not that it's declared as a Collection; it is a Set.

Related

Java Generics : Convert Object Array to Primitive Array based on type

I want to convert an Object array to primitive array based on type of elements present in array.
I want to implement a function which takes Object array and type(as String) as inputs and should return the actual array i.e
func(Object[] arr, String type) should be implemented so that when I call
func(Object[] arr, "int"), it should return int[]
func(Object[] arr, "double"), it should return double[] etc.
Is it possible to do this and if not what can be done to obtain primitive array from Object[] ?
Edit : The use case I have is I need to create 'n' objects of class A which has certain fields(lets say 2). I get fields as Object arrays of length n i.e
Object[] field1
Object[] field2
I also get type of field in String format("int" or "double" etc) which is primitive always. Now can we create objects of class A and if possible how?
Instead of pre-allocating an array, I would suggest using a collection like ArrayList and then generate the resultant array into it.
ArrayList field1Array = Arrays.stream(arr).map(Object::field1)
If there are more fields that need to be allocated, then...
ArrayList field1Array = new ArrayList();
ArrayList field2Array = new ArrayList();
Arrays.stream(arr).forEach(object -> {
field1Array.add(object.getField1());
field2Array.add(object.getField2());
})

misunderstanding the generic in java

I am trying to understand generics in Java.
private List<Own> l = new ArrayList<Own>();
I have the following error :
no instance of Typed array variable T exist so that List<Own> conform to T[]
when I pass it in a method (readTypedArray) that expects T[].
private List<Own> list = new ArrayList<Own>();
private OwnParceable(Parcel in) {
in.readTypedArray(list, CategoriesParceable.CREATOR);
}
The method in.readTypedArray() expects an array T[], but you passed a List<Own which is not an array.
List is not an array you can't use it where an array is expected, List is an interface which extends Collection while array is a data structure in Java, check Difference between List and Array for further details.
You can either declare an Own[]instead of List<Own> or convert this list into an array before passing it to the method, check Convert list to array in Java:
in.readTypedArray(list.toArray(new Own[list.size()]), CategoriesParceable.CREATOR);
This has nothing to do with generics - Lists and arrays are just two different things. If your method expects an array, you need to pass it an array, not a List:
Own[] arr = new Own[10]; // Or some size that makes sense...
in.readTypedArray(arr, CategoriesParceable.CREATOR);
There is a possibility to create an array filled with content of specified List. To achieve that you can call method toArray() of your list reference, for example:
Integer[] array = list.toArray(new Integer[list.size()]);

Can individual array references be made final? [duplicate]

Is there an immutable alternative to the primitive arrays in Java? Making a primitive array final doesn't actually prevent one from doing something like
final int[] array = new int[] {0, 1, 2, 3};
array[0] = 42;
I want the elements of the array to be unchangeable.
Not with primitive arrays. You'll need to use a List or some other data structure:
List<Integer> items = Collections.unmodifiableList(Arrays.asList(0,1,2,3));
My recommendation is to not use an array or an unmodifiableList but to use Guava's ImmutableList, which exists for this purpose.
ImmutableList<Integer> values = ImmutableList.of(0, 1, 2, 3);
As others have noted, you can't have immutable arrays in Java.
If you absolutely need a method that returns an array that doesn't influence the original array, then you'd need to clone the array each time:
public int[] getFooArray() {
return fooArray == null ? null : fooArray.clone();
}
Obviously this is rather expensive (as you'll create a full copy each time you call the getter), but if you can't change the interface (to use a List for example) and can't risk the client changing your internals, then it may be necessary.
This technique is called making a defensive copy.
There is one way to make an immutable array in Java:
final String[] IMMUTABLE = new String[0];
Arrays with 0 elements (obviously) cannot be mutated.
This can actually come in handy if you are using the List.toArray method to convert a List to an array. Since even an empty array takes up some memory, you can save that memory allocation by creating a constant empty array, and always passing it to the toArray method. That method will allocate a new array if the array you pass doesn't have enough space, but if it does (the list is empty), it will return the array you passed, allowing you to reuse that array any time you call toArray on an empty List.
final static String[] EMPTY_STRING_ARRAY = new String[0];
List<String> emptyList = new ArrayList<String>();
return emptyList.toArray(EMPTY_STRING_ARRAY); // returns EMPTY_STRING_ARRAY
As of Java 9 you can use List.of(...), JavaDoc.
This method returns an immutable List and is very efficient.
Another one answer
static class ImmutableArray<T> {
private final T[] array;
private ImmutableArray(T[] a){
array = Arrays.copyOf(a, a.length);
}
public static <T> ImmutableArray<T> from(T[] a){
return new ImmutableArray<T>(a);
}
public T get(int index){
return array[index];
}
}
{
final ImmutableArray<String> sample = ImmutableArray.from(new String[]{"a", "b", "c"});
}
Since Guava 22, from package com.google.common.primitives you can use three new classes, which have a lower memory footprint compared to ImmutableList.
ImmutableIntArray
ImmutableLongArray
ImmutableDoubleArray
They also have a builder. Example:
int size = 2;
ImmutableLongArray longArray = ImmutableLongArray.builder(size)
.add(1L)
.add(2L)
.build();
or, if the size is known at compile-time:
ImmutableLongArray longArray = ImmutableLongArray.of(1L, 2L);
This is another way of getting an immutable view of an array for Java primitives.
If you need (for performance reason or to save memory) native 'int' instead of 'java.lang.Integer', then you would probably need to write your own wrapper class. There are various IntArray implementations on the net, but none (I found) was immutable: Koders IntArray, Lucene IntArray. There are probably others.
The of(E... elements) method in Java9 can be used to create immutable list using just a line:
List<Integer> items = List.of(1,2,3,4,5);
The above method returns an immutable list containing an arbitrary number of elements. And adding any integer to this list would result in java.lang.UnsupportedOperationExceptionexception. This method also accepts a single array as an argument.
String[] array = ... ;
List<String[]> list = List.<String[]>of(array);
No, this is not possible. However, one could do something like this:
List<Integer> temp = new ArrayList<Integer>();
temp.add(Integer.valueOf(0));
temp.add(Integer.valueOf(2));
temp.add(Integer.valueOf(3));
temp.add(Integer.valueOf(4));
List<Integer> immutable = Collections.unmodifiableList(temp);
This requires using wrappers, and is a List, not an array, but is the closest you will get.
In some situations, it will be lighter weight to use this static method from Google Guava library: List<Integer> Ints.asList(int... backingArray)
Examples:
List<Integer> x1 = Ints.asList(0, 1, 2, 3)
List<Integer> x1 = Ints.asList(new int[] { 0, 1, 2, 3})
If you want to avoid both mutability and boxing, there is no way out of the box. But you can create a class which holds primitive array inside and provides read-only access to elements via method(s).
Implement java.util.function.IntUnaryOperator:
class ImmutableArray implements IntUnaryOperator {
private final int[] array;
ImmutableArray(int[] array) {
this.array = Arrays.copyOf(array, array.length);
}
#Override
public int applyAsInt(int index) {
return array[index];
}
}
Access the array: array[i] becomes immutableArray.applyAsInt(i).
I benchmarked primitive for loop retrieval with a modulus operation with 100_000_000 elements. The above PrimitiveArray took ~220ms; there was no significant difference with a primitive array. The same op on ArrayList took 480 ms, and the loading process took 21 seconds, depleted my heap space first try, and I had to increase this setting on the JVM. Loading of PrimitiveArray had taken 2 seconds.
iteration
if you want to iterate, implement Iterable and provide
public java.util.PrimitiveIterator.OfInt iterator() { return Arrays.stream(array).iterator(); }
This provides access to int nextInt method.
From PrimitiveIterator you also get method forEachRemaining(PrimitiveConsumer) which is helpful to replace an existing enhanced for loop.
Iterating manually with PrimitiveIterator.OfInt yielded performance of ~300ms.
While it's true that Collections.unmodifiableList() works, sometimes you may have a large library having methods already defined to return arrays (e.g. String[]).
To prevent breaking them, you can actually define auxiliary arrays that will store the values:
public class Test {
private final String[] original;
private final String[] auxiliary;
/** constructor */
public Test(String[] _values) {
original = new String[_values.length];
// Pre-allocated array.
auxiliary = new String[_values.length];
System.arraycopy(_values, 0, original, 0, _values.length);
}
/** Get array values. */
public String[] getValues() {
// No need to call clone() - we pre-allocated auxiliary.
System.arraycopy(original, 0, auxiliary, 0, original.length);
return auxiliary;
}
}
To test:
Test test = new Test(new String[]{"a", "b", "C"});
System.out.println(Arrays.asList(test.getValues()));
String[] values = test.getValues();
values[0] = "foobar";
// At this point, "foobar" exist in "auxiliary" but since we are
// copying "original" to "auxiliary" for each call, the next line
// will print the original values "a", "b", "c".
System.out.println(Arrays.asList(test.getValues()));
Not perfect, but at least you have "pseudo immutable arrays" (from the class perspective) and this will not break related code.
Well.. arrays are useful to pass as constants (if they were) as variants parameters.

Convert Java Array to Iterable

I have an Array of primitives, for example for int, int[] foo. It might be a small sized one, or not.
int foo[] = {1,2,3,4,5,6,7,8,9,0};
What is the best way to create an Iterable<Integer> from it?
Iterable<Integer> fooBar = convert(foo);
Notes:
Please do not answer using loops (unless you can give a good explanation on how the compiler do something smart about them?)
Also note that
int a[] = {1,2,3};
List<Integer> l = Arrays.asList(a);
Will not even compile
Type mismatch: cannot convert from List<int[]> to List<Integer>
Also check
Why is an array not assignable to Iterable?
before answering.
Also, if you use some library (e.g., Guava), please explain why this is the Best. ( Because its from Google is not a complete answer :P )
Last, since there seems to be a homework about that, avoid posting homeworkish code.
Integer foo[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
List<Integer> list = Arrays.asList(foo);
// or
Iterable<Integer> iterable = Arrays.asList(foo);
Though you need to use an Integer array (not an int array) for this to work.
For primitives, you can use guava:
Iterable<Integer> fooBar = Ints.asList(foo);
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>15.0</version>
<type>jar</type>
</dependency>
For Java8 with lambdas: (Inspired by Jin Kwon's answer)
final int[] arr = { 1, 2, 3 };
final Iterable<Integer> i1 = () -> Arrays.stream(arr).iterator();
final Iterable<Integer> i2 = () -> IntStream.of(arr).iterator();
final Iterable<Integer> i3 = () -> IntStream.of(arr).boxed().iterator();
just my 2 cents:
final int a[] = {1,2,3};
java.lang.Iterable<Integer> aIterable=new Iterable<Integer>() {
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
private int pos=0;
public boolean hasNext() {
return a.length>pos;
}
public Integer next() {
return a[pos++];
}
public void remove() {
throw new UnsupportedOperationException("Cannot remove an element of an array.");
}
};
}
};
With Java 8, you can do this.
final int[] arr = {1, 2, 3};
final PrimitiveIterator.OfInt i1 = Arrays.stream(arr).iterator();
final PrimitiveIterator.OfInt i2 = IntStream.of(arr).iterator();
final Iterator<Integer> i3 = IntStream.of(arr).boxed().iterator();
Guava provides the adapter you want as Int.asList(). There is an equivalent for each primitive type in the associated class, e.g., Booleans for boolean, etc.
int foo[] = {1,2,3,4,5,6,7,8,9,0};
Iterable<Integer> fooBar = Ints.asList(foo);
for(Integer i : fooBar) {
System.out.println(i);
}
The suggestions above to use Arrays.asList won't work, even if they compile because you get an Iterator<int[]> rather than Iterator<Integer>. What happens is that rather than creating a list backed by your array, you created a 1-element list of arrays, containing your array.
In Java 8 or later, Iterable is a functional interface returns Iterator.
So you can do this.
static Iterable<Integer> convert(int[] array) {
return () -> Arrays.stream(array).iterator();
}
and
int[] array = {1, 2, 3};
Iterable<Integer> iterable = convert(array);
for (int i : iterable)
System.out.println(i);
output:
1
2
3
I had the same problem and solved it like this:
final YourType[] yourArray = ...;
return new Iterable<YourType>() {
public Iterator<YourType> iterator() {
return Iterators.forArray(yourArray); // Iterators is a Google guava utility
}
}
The iterator itself is a lazy UnmodifiableIterator but that's exactly what I needed.
First of all, I can only agree that Arrays.asList(T...) is clearly the best solution for Wrapper types or arrays with non-primtive datatypes. This method calls a constructor of a simple private static AbstractList implementation in the Arrays class which basically saves the given array reference as field and simulates a list by overriding the needed methods.
If you can choose between a primtive type or a Wrapper type for your array, I would use the Wrapper type for such situations but of course, it's not always useful or required.
There would be only two possibilities you can do:
1) You can create a class with a static method for each primitive datatype array (boolean, byte, short, int, long, char, float, double returning an Iterable<WrapperType>. These methods would use anonymous classes of Iterator (besides Iterable) which are allowed to contain the reference of the comprising method's argument (for example an int[]) as field in order to implement the methods.
-> This approach is performant and saves you memory (except for the memory of the newly created methods, even though, using Arrays.asList() would take memory in the same way)
2) Since arrays don't have methods (as to be read on the side you linked) they can't provide an Iterator instance either. If you really are too lazy to write new classes, you must use an instance of an already existing class that implements Iterable because there is no other way around than instantiating Iterable or a subtype.
The ONLY way to create an existing Collection derivative implementing Iterable is to use a loop (except you use anonymous classes as described above) or you instantiate an Iterable implementing class whose constructor allows a primtive type array (because Object[] doesn't allow arrays with primitive type elements) but as far as I know, the Java API doesn't feature a class like that.The reason for the loop can be explained easily:for each Collection you need Objects and primtive datatypes aren't objects. Objects are much bigger than primitive types so that they require additional data which must be generated for each element of the primitive type array. That means if two ways of three (using Arrays.asList(T...) or using an existing Collection) require an aggregate of objects, you need to create for each primitive value of your int[] array the wrapper object. The third way would use the array as is and use it in an anonymous class as I think it's preferable due to fast performance.
There is also a third strategy using an Object as argument for the method where you want to use the array or Iterable and it would require type checks to figure out which type the argument has, however I wouldn't recommend it at all as you usually need to consider that the Object hasn't always the required type and that you need seperate code for certain cases.
In conclusion, it's the fault of Java's problematic Generic Type system which doesn't allow to use primitive types as generic type which would save a lot of code by using simply Arrays.asList(T...). So you need to program for each primitive type array, you need, such a method (which basically makes no difference to the memory used by a C++ program which would create for each used type argument a seperate method.
You can use IterableOf from Cactoos:
Iterable<String> names = new IterableOf<>(
"Scott Fitzgerald", "Fyodor Dostoyevsky"
);
Then, you can turn it into a list using ListOf:
List<String> names = new ListOf<>(
new IterableOf<>(
"Scott Fitzgerald", "Fyodor Dostoyevsky"
)
);
Or simply this:
List<String> names = new ListOf<>(
"Scott Fitzgerald", "Fyodor Dostoyevsky"
);
While a similar answer has already been sort of posted, I think the reason to use the new PrimitiveIterator.OfInt was not clear. A good solution is to use Java 8 PrimitiveIterator since it's specialized for primitive int types (and avoids the extra boxing/unboxing penalty):
int[] arr = {1,2,3};
// If you use Iterator<Integer> here as type then you can't get the actual benefit of being able to use nextInt() later
PrimitiveIterator.OfInt iterator = Arrays.stream(arr).iterator();
while (iterator.hasNext()) {
System.out.println(iterator.nextInt());
// Use nextInt() instead of next() here to avoid extra boxing penalty
}
Ref: https://doc.bccnsoft.com/docs/jdk8u12-docs/api/java/util/PrimitiveIterator.OfInt.html
In java8 IntSteam stream can be boxed to stream of Integers.
public static Iterable<Integer> toIterable(int[] ints) {
return IntStream.of(ints).boxed().collect(Collectors.toList());
}
I think performance matters based on the size of the array.

Arrays.asList(T[] array)?

So there's Arrays.asList(T... a) but this works on varargs.
What if I already have the array in a T[] a? Is there a convenience method to create a List<T> out of this, or do I have to do it manually as:
static public <T> List<T> arrayAsList(T[] a)
{
List<T> result = new ArrayList<T>(a.length);
for (T t : a)
result.add(t);
return result;
}
Just because it works with varargs doesn't mean you can't call it normally:
String[] x = { "a", "b", "c" };
List<String> list = Arrays.asList(x);
The only tricky bit is if T is Object, where you should use a cast to tell the compiler whether it should wrap the argument in an array or not:
Object[] x = ...;
List<Object> list = Arrays.asList((Object[]) x);
or
Object[] x = ...;
List<Object[]> list = Arrays.asList((Object) x);
As you probably already know, there is a Static class called java.util.Collections which has a number of useful methods for dealing wit arrays such as searching and sorting.
As for your question, the Collection interface specifies methods to add, remove and toArray, amongst others. For one reason or another, the API's authors decided that the add and addAll method will be the only input functions provided to the user.
One explanation for why Java Lists cannot add arrays of objects is that Lists use an iterator and iterators are more strict in their scrolling (i.e. going to the next value) than Arrays which do not have to have all their index values i=(1, 2, 5, 9, 22, ...).
Also, Arrays are not type safe; that is, they cannot guarantee that all their elements conform to a specific super-class or interface, whereas generics (of which List is a member) can guarantee type safety. Hence, the list has the chance to validate each item using the add method.
I think that you can rest assure that your method of adding an array to a list is one of the most (if not most) efficient way of achieving this effect in Java.

Categories