I have a a List of Objects. Those Objects have (amongst others) a private int Array (if it helps, I can transfer it into a List). There is a public Getter for this Array. All Arrays are the same size.
I want to sort the Object based on their Arrays like this:
Unsorted:
{[0, 1, 4, 5],
[0, 0, 2, 3],
[0, 1, 1, 2]}
Sorted:
{[0, 0, 2, 3],
[0, 1, 1, 2],
[0, 1, 4, 5]}
In Words (it's called lexicographical):
compare the first int of each array
if they are equal, compare the next int of each array (and so on)
if they aren't equal the result of the comparison is the end result.
I manage to search them for e.g. only the first element of the array with a normal Comparator but I don't know how to search them for all.
A nice Java 8 solution is
static final Comparator<CustomObject> COMPARATOR = (o1, o2) -> {
int[] arr1 = o1.getArray();
int[] arr2 = o2.getArray();
return IntStream.range(0, arr1.length)
.map(i -> Integer.compare(arr1[i], arr2[i]))
.filter(i -> i != 0)
.findFirst()
.orElse(0);
};
Then, given a List<CustomObject>, you can do
list.sort(COMPARATOR);
(The Comparator only works for arrays of the same length. You may want to modify it).
I have a Collection (preferable some kind of List) of Objects
[...]
Now I want to sort the Object based on their Arrays
For it to be meaningful at all, the Collection in question must be one that preserves order and allows you to reorder elements. In terms of the high-level Collections interfaces, only List has the required properties, so let's presume that your Collection is, indeed, a List.
The standard way to sort a List is to use one of the two Collections.sort() methods. One requires the list elements to implement Comparable, and the other, more general, one requires you to provide an object implementing Comparator for use in determining the desired relative order of the objects.
Arrays do not implement Comparable (which is equivalent to saying that they have no "natural order"), but the class of the objects containing them could be made to do so. It is probably better form, however, to write a separate Comparator class that implements the order you want, and use an instance of that class.
If I am understanding it correctly, following straightforward approach should work:
public class SortArrays {
public static void main(String[] args) {
List<int[]> listOfArrays = new ArrayList<>(4);
listOfArrays.add(new int[]{0, 1, 4, 5});
listOfArrays.add(new int[]{0, 0, 2, 3});
listOfArrays.add(new int[]{0, 1, 1, 2});
Collections.sort(listOfArrays, (o1, o2) -> {
for (int i = 0; i < o1.length; i++) {
if (o1[i] < o2[i])
return -1;
if (o1[i] > o2[i])
return 1;
}
return 0;
});
listOfArrays.forEach(a -> System.out.println(Arrays.toString(a)));
}
}
It produces:
[0, 0, 2, 3]
[0, 1, 1, 2]
[0, 1, 4, 5]
and that's what you seem to expect.
Suppose your class looks something like this, and you can't modify it.
final class MyClass
{
private final int[] key;
MyClass(int[] key)
{
this.key = key.clone();
}
public int[] getKey()
{
return key.clone();
}
}
Then, you can define an ordering for instances of MyClass by implementing the Comparator interface. To be more general, I'm actually going to implement a comparator for int[]:
final class IntArrayComparator
implements Comparator<int[]>
{
#Override
public int compare(int[] a, int[] b)
{
int n = Math.min(a.length, b.length);
for (int idx = 0; idx < n; ++idx) {
if (a[idx] != b[idx])
return (a[idx] < b[idx]) ? -1 : +1;
}
return a.length - b.length;
}
}
Given this new comparator, and your existing type, it's easy to sort:
final class Test
{
public static void main(String... arg)
{
/* Create your list somehow... */
List<MyClass> list = new ArrayList<>();
list.add(new MyClass(new int[]{0, 1, 4, 5}));
list.add(new MyClass(new int[]{0, 0, 2, 3}));
list.add(new MyClass(new int[]{0, 1, 1, 2}));
/* Now sort the list. */
list.sort(Comparator.comparing(MyClass::getKey, new IntArrayComparator()));
/* Display the result... */
list.stream().map(MyClass::getKey).map(Arrays::toString).forEach(System.out::println);
}
}
You should get the output:
[0, 0, 2, 3]
[0, 1, 1, 2]
[0, 1, 4, 5]
The comparing() factory method I am using takes two arguments: a Function to "extract" a key from each object in the list, and a Comparator that can compare the extracted keys. If the extracted key has a natural ordering, and implements Comparable (for example, it's a String), then it isn't necessary to specify a Comparator.
Alternatively, if you can modify MyClass, you could give it a natural order by implementing Comparable and moving the int[] comparison to its compareTo() method, as shown in other answers. Then you can use the sort() method without arguments.
In order to sort a list of arrays of int, you want a function that performs a lexicographic comparison of an array of ints. This is usually expressed as a Comparator<int[]> in Java. The usual way to implement such a function is to compare corresponding values left-to-right until a mismatch is found; that mismatch determines the order. If the end of an array is reached without finding a mismatch, the shorter array is usually considered less than the longer one. If the lengths are equal, and all values are equal, the arrays are considered equal.
Other answers have used anonymous inner classes or lambdas for this function, but for things like this I prefer an ordinary method that has the right "shape", that is, that takes two int[] arguments and returns an int which is the result of the comparison. This enables it to be used as the target of a method reference.
int arrayCompare(int[] a, int[] b) {
int len = Math.min(a.length, b.length);
for (int i = 0; i < len; i++) {
int c = Integer.compare(a[i], b[i]);
if (c != 0) {
return c;
}
}
return a.length - b.length;
}
Note the careful use of Integer.compare() instead of subtraction, avoiding potential problems with overflow. Usage would be as follows:
List<int[]> arrays = Arrays.asList(
new int[] { 0, 1, 4, 5 },
new int[] { 0, 0, 2, 3 },
new int[] { 0, 1, 1, 2 }
);
arrays.sort(this::arrayCompare);
arrays.forEach(a -> System.out.println(Arrays.toString(a)));
In JDK 9, lexicographic array comparison functions have been added to the Arrays class. See Arrays.compare(int[], int[]). There are also overloads for the other primitive types and for reference types. The int[] overload replaces the arrayCompare function I wrote above, so you can rewrite the sort call as follows:
arrays.sort(Arrays::compare);
The advantage of the comparison functions in the Arrays class is that they can be handled specially by the JVM, which can, for example, use vector instructions to speed up array comparisons.
For your specific problem, it looks like you don't have a list of int[], but you have a list of objects of type MyObject that have an int[] that you want to use as the sort key. Suppose the way to get the array is by calling the method getArray(). You can sort the list as follows:
myObjects.sort(Comparator.comparing(MyObject::getArray, Arrays::compare));
Consider this object:
public class Foo {
private int[] values;
public Foo(int[] values) {
this.values = values;
}
}
To make a list of objects:
ArrayList<Foo> foos = new ArrayList<>();
foos.add(new Foo(new int[] {0, 1, 4, 5}));
foos.add(new Foo(new int[] {0, 0, 2, 3}));
foos.add(new Foo(new int[] {0, 1, 1, 2}));
Now we want to sort our list of objects, so the first thing we should do is make our object implement Comparable. You should read more what the Comparable interface is, and how to implement it.
public class Foo implements Comparable<Foo> {
...
}
At this point your compiler will complain that you haven't implemented all of the methods required by the interface. So do that.
public class Foo implements Comparable<Foo> {
...
public int compareTo(Foo f) {
// Return a negative integer if this < f
// Return zero if this == f
// Return a positive integer if this > f
}
}
As far as the actual comparison logic goes, your question is not very specific about the exact rules you are using to compare two objects. However, from the example, I can kind of guess that these are your rules:
Compare the first number of each array.
If they are equal, repeat this process using the next number of each array.
Otherwise, the result of this comparison is the final result.
You don't really specify what to do if one array is shorter than the other. I'll leave writing the actual algorithm to you (although others answers appear to have done that for you). However, I will point out that because values is a private field, you won't be able to use that field for comparison unless you implement a getter for the field or make it public.
public int[] getValues() { return values; }
If your array is private and you do want to provide an accessor method then implement Comparable for the class and do something like below code.
If you have an accessor method then do this in a Comparator.
This code does not assume arrays to be of same size so it works for different size arrays. Please change according to your need.
PS - not compiled/tested
public int compareTo(Object o) {
CustomClass other = (CustomClass ) o;
int i = 0;
while (i <= numbers.length && i <= other.numbers.length) {
if (numbers[i] < other.numbers[i])
return -1;
else if (numbers[i] > other.numbers[i])
return 1;
++i;
}
if (numbers.length < other.numbers.length)
return -1;
else if (numbers.length > other.numbers.length)
return 1;
return 0;
}
Related
This question already has answers here:
How to convert an ArrayList containing Integers to primitive int array?
(19 answers)
Closed 4 years ago.
How can I convert a List<Integer> to int[] in Java?
I'm confused because List.toArray() actually returns an Object[], which can be cast to neither Integer[] nor int[].
Right now I'm using a loop to do so:
int[] toIntArray(List<Integer> list) {
int[] ret = new int[list.size()];
for(int i = 0; i < ret.length; i++)
ret[i] = list.get(i);
return ret;
}
Is there's a better way to do this?
This is similar to the question
How can I convert int[] to Integer[] in Java?.
With streams added in Java 8 we can write code like:
int[] example1 = list.stream().mapToInt(i->i).toArray();
// OR
int[] example2 = list.stream().mapToInt(Integer::intValue).toArray();
Thought process:
The simple Stream#toArray returns an Object[] array, so it is not what we want. Also, Stream#toArray(IntFunction<A[]> generator) doesn't do what we want, because the generic type A can't represent the primitive type int
So it would be nice to have some stream which could handle the primitive type int instead of the wrapper Integer, because its toArray method will most likely also return an int[] array (returning something else like Object[] or even boxed Integer[] would be unnatural here). And fortunately Java 8 has such a stream which is IntStream
So now the only thing we need to figure out is how to convert our Stream<Integer> (which will be returned from list.stream()) to that shiny IntStream.
Quick searching in documentation of Stream while looking for methods which return IntStream points us to our solution which is mapToInt(ToIntFunction<? super T> mapper) method. All we need to do is provide a mapping from Integer to int.
Since ToIntFunction is functional interface we can provide its instance via lambda or method reference.
Anyway to convert Integer to int we can use Integer#intValue so inside mapToInt we can write:
mapToInt( (Integer i) -> i.intValue() )
(or some may prefer: mapToInt(Integer::intValue).)
But similar code can be generated using unboxing, since the compiler knows that the result of this lambda must be of type int (the lambda used in mapToInt is an implementation of the ToIntFunction interface which expects as body a method of type: int applyAsInt(T value) which is expected to return an int).
So we can simply write:
mapToInt((Integer i)->i)
Also, since the Integer type in (Integer i) can be inferred by the compiler because List<Integer>#stream() returns a Stream<Integer>, we can also skip it which leaves us with
mapToInt(i -> i)
Unfortunately, I don't believe there really is a better way of doing this due to the nature of Java's handling of primitive types, boxing, arrays and generics. In particular:
List<T>.toArray won't work because there's no conversion from Integer to int
You can't use int as a type argument for generics, so it would have to be an int-specific method (or one which used reflection to do nasty trickery).
I believe there are libraries which have autogenerated versions of this kind of method for all the primitive types (i.e. there's a template which is copied for each type). It's ugly, but that's the way it is I'm afraid :(
Even though the Arrays class came out before generics arrived in Java, it would still have to include all the horrible overloads if it were introduced today (assuming you want to use primitive arrays).
In addition to Commons Lang, you can do this with Guava's method Ints.toArray(Collection<Integer> collection):
List<Integer> list = ...
int[] ints = Ints.toArray(list);
This saves you having to do the intermediate array conversion that the Commons Lang equivalent requires yourself.
The easiest way to do this is to make use of Apache Commons Lang. It has a handy ArrayUtils class that can do what you want. Use the toPrimitive method with the overload for an array of Integers.
List<Integer> myList;
... assign and fill the list
int[] intArray = ArrayUtils.toPrimitive(myList.toArray(new Integer[myList.size()]));
This way you don't reinvent the wheel. Commons Lang has a great many useful things that Java left out. Above, I chose to create an Integer list of the right size. You can also use a 0-length static Integer array and let Java allocate an array of the right size:
static final Integer[] NO_INTS = new Integer[0];
....
int[] intArray2 = ArrayUtils.toPrimitive(myList.toArray(NO_INTS));
Java 8 has given us an easy way to do this via streams...
Using the collections stream() function and then mapping to ints, you'll get an IntStream. With the IntStream we can call toArray() which gives us int []
int [] ints = list.stream().mapToInt(Integer::intValue).toArray();
to int []
to IntStream
Use:
int[] toIntArray(List<Integer> list) {
int[] ret = new int[list.size()];
int i = 0;
for (Integer e : list)
ret[i++] = e;
return ret;
}
This slight change to your code is to avoid expensive list indexing (since a List is not necessarily an ArrayList, but it could be a linked list, for which random access is expensive).
Here is a Java 8 single line code for this:
public int[] toIntArray(List<Integer> intList){
return intList.stream().mapToInt(Integer::intValue).toArray();
}
If you are simply mapping an Integer to an int then you should consider using parallelism, since your mapping logic does not rely on any variables outside its scope.
int[] arr = list.parallelStream().mapToInt(Integer::intValue).toArray();
Just be aware of this
Note that parallelism is not automatically faster than performing operations serially, although it can be if you have enough data and processor cores. While aggregate operations enable you to more easily implement parallelism, it is still your responsibility to determine if your application is suitable for parallelism.
There are two ways to map Integers to their primitive form:
Via a ToIntFunction.
mapToInt(Integer::intValue)
Via explicit unboxing with lambda expression.
mapToInt(i -> i.intValue())
Via implicit (auto-) unboxing with lambda expression.
mapToInt(i -> i)
Given a list with a null value
List<Integer> list = Arrays.asList(1, 2, null, 4, 5);
Here are three options to handle null:
Filter out the null values before mapping.
int[] arr = list.parallelStream().filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();
Map the null values to a default value.
int[] arr = list.parallelStream().map(i -> i == null ? -1 : i).mapToInt(Integer::intValue).toArray();
Handle null inside the lambda expression.
int[] arr = list.parallelStream().mapToInt(i -> i == null ? -1 : i.intValue()).toArray();
This simple loop is always correct! no bugs
int[] integers = new int[myList.size()];
for (int i = 0; i < integers.length; i++) {
integers[i] = myList.get(i);
}
I've noticed several uses of for loops, but you don't even need anything inside the loop. I mention this only because the original question was trying to find less verbose code.
int[] toArray(List<Integer> list) {
int[] ret = new int[ list.size() ];
int i = 0;
for( Iterator<Integer> it = list.iterator();
it.hasNext();
ret[i++] = it.next() );
return ret;
}
If Java allowed multiple declarations in a for loop the way C++ does, we could go a step further and do for(int i = 0, Iterator it...
In the end though (this part is just my opinion), if you are going to have a helping function or method to do something for you, just set it up and forget about it. It can be a one-liner or ten; if you'll never look at it again you won't know the difference.
There is really no way of "one-lining" what you are trying to do, because toArray returns an Object[] and you cannot cast from Object[] to int[] or Integer[] to int[].
int[] ret = new int[list.size()];
Iterator<Integer> iter = list.iterator();
for (int i=0; iter.hasNext(); i++) {
ret[i] = iter.next();
}
return ret;
Also try Dollar (check this revision):
import static com.humaorie.dollar.Dollar.*
...
List<Integer> source = ...;
int[] ints = $(source).convert().toIntArray();
With Eclipse Collections, you can do the following if you have a list of type java.util.List<Integer>:
List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = LazyIterate.adapt(integers).collectInt(i -> i).toArray();
Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);
If you already have an Eclipse Collections type like MutableList, you can do the following:
MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = integers.asLazy().collectInt(i -> i).toArray();
Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);
Note: I am a committer for Eclipse Collections
I would recommend you to use the List<?> skeletal implementation from the Java collections API. It appears to be quite helpful in this particular case:
package mypackage;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Test {
// Helper method to convert int arrays into Lists
static List<Integer> intArrayAsList(final int[] a) {
if(a == null)
throw new NullPointerException();
return new AbstractList<Integer>() {
#Override
public Integer get(int i) {
return a[i]; // Autoboxing
}
#Override
public Integer set(int i, Integer val) {
final int old = a[i];
a[i] = val; // Auto-unboxing
return old; // Autoboxing
}
#Override
public int size() {
return a.length;
}
};
}
public static void main(final String[] args) {
int[] a = {1, 2, 3, 4, 5};
Collections.reverse(intArrayAsList(a));
System.out.println(Arrays.toString(a));
}
}
Beware of boxing/unboxing drawbacks.
Using a lambda you could do this (compiles in JDK lambda):
public static void main(String ars[]) {
TransformService transformService = (inputs) -> {
int[] ints = new int[inputs.size()];
int i = 0;
for (Integer element : inputs) {
ints[ i++ ] = element;
}
return ints;
};
List<Integer> inputs = new ArrayList<Integer>(5) { {add(10); add(10);} };
int[] results = transformService.transform(inputs);
}
public interface TransformService {
int[] transform(List<Integer> inputs);
}
I have a map from List to String (keys are lists).
the keys are converted from int arrays to lists.
adding a pair example:
int[] arr = { 1, 2, 3, 4, 5 };
my_map.put(Arrays.asList(arr), "12345");
Now when i check if my_map contains some other list, i will always get null, example:
int[] test_arr = { 1, 2, 3, 4, 5 };
if (my_map.get(Arrays.asList(test_arr)) != null) { // always null!
// do something
}
I know what the problem is: it's comparing the addresses of the lists, and NOT the values!
How can i compare those lists values ?
The problem you mentioned is correct, I’ll suggest replacing the key value to be string to list. But if you insist for your reasons you can envelope the list implementation with your own class and override the equal to function to be based on the values and not the address.
Some map implementations allow you to instantiate your map with a Comparator (TreeMap for example).
This way you can provide your own implementation to determine if the Keys are equal.
Your comparator function returns an int with a value that is greater than zero, less than zero, or zero if the two values are equal.
My advice is to change a little bit the storage in order to have the same functionality. Means to check if a predefined list is within the stucture.
You do not need a Map since it's not required to add values, just use the values within List. Further more use Objects and not primitives.
Briefly a List of Lists will fit well in this case. Notice, the order of elements in List matters. If do not care order you could just sort both lists before compare.
public class TestListArr {
public static void main(String[] args) {
List<List<Integer>> list = new ArrayList<>();
Integer[] arr = { 1, 2, 3, 4, 5 };
//just check it
//int[] arr1 = {1,2,3};
//Arrays.asList(arr1).forEach(System.out::println);
//Arrays.asList(arr).forEach(System.out::println);
list.add(Arrays.asList(arr));
Integer[] test_true = { 1, 2, 3, 4, 5 };
System.out.println(check(list,test_true));
Integer[] test_false = { 1, 2, 3, 4 };
System.out.println(check(list,test_false));
//direct test
//System.out.println(Arrays.asList(arr).equals(Arrays.asList(test_true)));
}
public static boolean check(List<List<Integer>> list, Integer[] test)
{
for(List<Integer> lst:list)
{
if(lst.equals(Arrays.asList(test)))
return true;
}
return false;
}
}
Output
true
false
The List objects that you are creating only contain one element, an object of type int[]. int[] uses identity to test equality, not array content. Instead, convert the array content to a list with equivalent content:
static List<Integer> toList(int[] arr) {
return IntStream.of(arr).boxed().collect(Collectors.toList());
}
I am trying to make a list with some array, generated random, within a range and with a fixed size. The problem is, when I want to see if an array is already in the list (list.contains(array)) it's not returning the good boolean variable. This is how this code looks like, and I have no idea from where's the problem:
List<int[]> list = new ArrayList<int[]>();
int[] v = new int[n];
int n = 2, val_max = 3;
while (list.size() != max) {
v = getRandomArray(n, 1, val_max);
if (list.contains(v) == false)
list.add(v);
}
I expect the output for that to be { {1, 2} {2, 1} {1, 3} {3, 1} {2, 3} {3, 2} } but the output keeps changing... It always doubles one or two of the above values which is what made me think that the problem must be from the contains function.
List.contains uses Object.equals to check for equality, but arrays use reference equality, not content equality. So .contains will always return false.
Unfortunately, for arrays specifically, there really are only two options:
Rewrite the logic of contains yourself, using Arrays.equals.
Wrap the arrays in a new object of your own creation and write its equality methods appropriately.
This question already has answers here:
How to convert an ArrayList containing Integers to primitive int array?
(19 answers)
Closed 4 years ago.
How can I convert a List<Integer> to int[] in Java?
I'm confused because List.toArray() actually returns an Object[], which can be cast to neither Integer[] nor int[].
Right now I'm using a loop to do so:
int[] toIntArray(List<Integer> list) {
int[] ret = new int[list.size()];
for(int i = 0; i < ret.length; i++)
ret[i] = list.get(i);
return ret;
}
Is there's a better way to do this?
This is similar to the question
How can I convert int[] to Integer[] in Java?.
With streams added in Java 8 we can write code like:
int[] example1 = list.stream().mapToInt(i->i).toArray();
// OR
int[] example2 = list.stream().mapToInt(Integer::intValue).toArray();
Thought process:
The simple Stream#toArray returns an Object[] array, so it is not what we want. Also, Stream#toArray(IntFunction<A[]> generator) doesn't do what we want, because the generic type A can't represent the primitive type int
So it would be nice to have some stream which could handle the primitive type int instead of the wrapper Integer, because its toArray method will most likely also return an int[] array (returning something else like Object[] or even boxed Integer[] would be unnatural here). And fortunately Java 8 has such a stream which is IntStream
So now the only thing we need to figure out is how to convert our Stream<Integer> (which will be returned from list.stream()) to that shiny IntStream.
Quick searching in documentation of Stream while looking for methods which return IntStream points us to our solution which is mapToInt(ToIntFunction<? super T> mapper) method. All we need to do is provide a mapping from Integer to int.
Since ToIntFunction is functional interface we can provide its instance via lambda or method reference.
Anyway to convert Integer to int we can use Integer#intValue so inside mapToInt we can write:
mapToInt( (Integer i) -> i.intValue() )
(or some may prefer: mapToInt(Integer::intValue).)
But similar code can be generated using unboxing, since the compiler knows that the result of this lambda must be of type int (the lambda used in mapToInt is an implementation of the ToIntFunction interface which expects as body a method of type: int applyAsInt(T value) which is expected to return an int).
So we can simply write:
mapToInt((Integer i)->i)
Also, since the Integer type in (Integer i) can be inferred by the compiler because List<Integer>#stream() returns a Stream<Integer>, we can also skip it which leaves us with
mapToInt(i -> i)
Unfortunately, I don't believe there really is a better way of doing this due to the nature of Java's handling of primitive types, boxing, arrays and generics. In particular:
List<T>.toArray won't work because there's no conversion from Integer to int
You can't use int as a type argument for generics, so it would have to be an int-specific method (or one which used reflection to do nasty trickery).
I believe there are libraries which have autogenerated versions of this kind of method for all the primitive types (i.e. there's a template which is copied for each type). It's ugly, but that's the way it is I'm afraid :(
Even though the Arrays class came out before generics arrived in Java, it would still have to include all the horrible overloads if it were introduced today (assuming you want to use primitive arrays).
In addition to Commons Lang, you can do this with Guava's method Ints.toArray(Collection<Integer> collection):
List<Integer> list = ...
int[] ints = Ints.toArray(list);
This saves you having to do the intermediate array conversion that the Commons Lang equivalent requires yourself.
The easiest way to do this is to make use of Apache Commons Lang. It has a handy ArrayUtils class that can do what you want. Use the toPrimitive method with the overload for an array of Integers.
List<Integer> myList;
... assign and fill the list
int[] intArray = ArrayUtils.toPrimitive(myList.toArray(new Integer[myList.size()]));
This way you don't reinvent the wheel. Commons Lang has a great many useful things that Java left out. Above, I chose to create an Integer list of the right size. You can also use a 0-length static Integer array and let Java allocate an array of the right size:
static final Integer[] NO_INTS = new Integer[0];
....
int[] intArray2 = ArrayUtils.toPrimitive(myList.toArray(NO_INTS));
Java 8 has given us an easy way to do this via streams...
Using the collections stream() function and then mapping to ints, you'll get an IntStream. With the IntStream we can call toArray() which gives us int []
int [] ints = list.stream().mapToInt(Integer::intValue).toArray();
to int []
to IntStream
Use:
int[] toIntArray(List<Integer> list) {
int[] ret = new int[list.size()];
int i = 0;
for (Integer e : list)
ret[i++] = e;
return ret;
}
This slight change to your code is to avoid expensive list indexing (since a List is not necessarily an ArrayList, but it could be a linked list, for which random access is expensive).
Here is a Java 8 single line code for this:
public int[] toIntArray(List<Integer> intList){
return intList.stream().mapToInt(Integer::intValue).toArray();
}
If you are simply mapping an Integer to an int then you should consider using parallelism, since your mapping logic does not rely on any variables outside its scope.
int[] arr = list.parallelStream().mapToInt(Integer::intValue).toArray();
Just be aware of this
Note that parallelism is not automatically faster than performing operations serially, although it can be if you have enough data and processor cores. While aggregate operations enable you to more easily implement parallelism, it is still your responsibility to determine if your application is suitable for parallelism.
There are two ways to map Integers to their primitive form:
Via a ToIntFunction.
mapToInt(Integer::intValue)
Via explicit unboxing with lambda expression.
mapToInt(i -> i.intValue())
Via implicit (auto-) unboxing with lambda expression.
mapToInt(i -> i)
Given a list with a null value
List<Integer> list = Arrays.asList(1, 2, null, 4, 5);
Here are three options to handle null:
Filter out the null values before mapping.
int[] arr = list.parallelStream().filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();
Map the null values to a default value.
int[] arr = list.parallelStream().map(i -> i == null ? -1 : i).mapToInt(Integer::intValue).toArray();
Handle null inside the lambda expression.
int[] arr = list.parallelStream().mapToInt(i -> i == null ? -1 : i.intValue()).toArray();
This simple loop is always correct! no bugs
int[] integers = new int[myList.size()];
for (int i = 0; i < integers.length; i++) {
integers[i] = myList.get(i);
}
I've noticed several uses of for loops, but you don't even need anything inside the loop. I mention this only because the original question was trying to find less verbose code.
int[] toArray(List<Integer> list) {
int[] ret = new int[ list.size() ];
int i = 0;
for( Iterator<Integer> it = list.iterator();
it.hasNext();
ret[i++] = it.next() );
return ret;
}
If Java allowed multiple declarations in a for loop the way C++ does, we could go a step further and do for(int i = 0, Iterator it...
In the end though (this part is just my opinion), if you are going to have a helping function or method to do something for you, just set it up and forget about it. It can be a one-liner or ten; if you'll never look at it again you won't know the difference.
There is really no way of "one-lining" what you are trying to do, because toArray returns an Object[] and you cannot cast from Object[] to int[] or Integer[] to int[].
int[] ret = new int[list.size()];
Iterator<Integer> iter = list.iterator();
for (int i=0; iter.hasNext(); i++) {
ret[i] = iter.next();
}
return ret;
Also try Dollar (check this revision):
import static com.humaorie.dollar.Dollar.*
...
List<Integer> source = ...;
int[] ints = $(source).convert().toIntArray();
With Eclipse Collections, you can do the following if you have a list of type java.util.List<Integer>:
List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = LazyIterate.adapt(integers).collectInt(i -> i).toArray();
Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);
If you already have an Eclipse Collections type like MutableList, you can do the following:
MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int[] ints = integers.asLazy().collectInt(i -> i).toArray();
Assert.assertArrayEquals(new int[]{1, 2, 3, 4, 5}, ints);
Note: I am a committer for Eclipse Collections
I would recommend you to use the List<?> skeletal implementation from the Java collections API. It appears to be quite helpful in this particular case:
package mypackage;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Test {
// Helper method to convert int arrays into Lists
static List<Integer> intArrayAsList(final int[] a) {
if(a == null)
throw new NullPointerException();
return new AbstractList<Integer>() {
#Override
public Integer get(int i) {
return a[i]; // Autoboxing
}
#Override
public Integer set(int i, Integer val) {
final int old = a[i];
a[i] = val; // Auto-unboxing
return old; // Autoboxing
}
#Override
public int size() {
return a.length;
}
};
}
public static void main(final String[] args) {
int[] a = {1, 2, 3, 4, 5};
Collections.reverse(intArrayAsList(a));
System.out.println(Arrays.toString(a));
}
}
Beware of boxing/unboxing drawbacks.
Using a lambda you could do this (compiles in JDK lambda):
public static void main(String ars[]) {
TransformService transformService = (inputs) -> {
int[] ints = new int[inputs.size()];
int i = 0;
for (Integer element : inputs) {
ints[ i++ ] = element;
}
return ints;
};
List<Integer> inputs = new ArrayList<Integer>(5) { {add(10); add(10);} };
int[] results = transformService.transform(inputs);
}
public interface TransformService {
int[] transform(List<Integer> inputs);
}
Let's say I have a list (EG: LinkedList<SomeObject>that contains elements ordered by a certain attribute (EG: SomeObject.someValue()). This attribute can and usually does repeat often/it isn't unique, BUT is never null.
Is there a convenient way to divide this into multiple Lists, each list containing only its equal in cardinal order? Also, can this be done with only once iteration of the list? For example, the original list:
1, 1, 1, 2, 2, 3, 3, 3
The desired lists from this:
1, 1, 1
2, 2,
3, 3, 3
Not too convenient, but:
start a loop. Store the previous item, and compare it to the current.
if the previous is different from the current (using equals(..), and be careful with null), then create a new List, or use list.subList(groupStart, currentIdx)
You could use Apache CollectionUtils to do this, where "list" is the original list, and "value" is the current value of the objects you want to extract a sublist for:
Collection<SomeObject> selectedObjects = CollectionUtils
.select(list,
new Predicate() {
boolean evaluate(Object input) {
return ((SomeObject) input).someValue().equals(value);
}
});
This approach means using a well known and well tested library (which always is a good thing), but the downside is that you will loop through the list once for each sublist you need.
Pretty sure there isn't a java API method for this. However you can write:
// This assumes your list is sorted according to someValue()
// SomeValueType is the type of SomeObject.someValue()
public Map<SomeValueType, List<SomeObject>> partition(List<SomeObject> list) {
Object currValue = null;
HashMap<SomeValueType, LinkedList<SomeObject>> result = new HashMap<SomeValueType, LinkedList<SomeObject>>();
LinkedList<SomeObject> currList = null;
for (SomeObject obj : list) {
if (!obj.someValue().equals(currValue()) {
currValue = obj.someValue();
currList = new LinkedList<SomeObject>();
result.put(currValue, currList);
}
currList.add(obj);
}
}
This will return you an HashMap of sublists, where the key is the someValue and the value is the partitioned list associated to it. Note, I didn't test this, so don't just copy the code.
EDIT: made this return hashmap instead of arraylist.
If you would use Google Guava-libaries:
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Lists;
public class Example {
public static void main(String[] args) {
HashMultiset<Integer> ints = HashMultiset.create();
ints.addAll(Lists.newArrayList(1, 1, 1, 2, 2, 3, 3, 3));
System.out.println(ints);
}
}
Output:
[1 x 3, 2 x 2, 3 x 3]
If you need to count how many elements of x you have use ints.count(x);, if you have value types you do not need to have more then just count.
With Guava, use Multimaps.index(Iterable<V>, Function<? super V, K>).
This should work (untested, but I am pretty sure everything is ok, This also assumes that the contents of the list are sortable):
public static List[] getEquivalentSubLists( List parent )
{
List cloneList = parent.clone();
Collections.sort(cloneList);
ArrayList<List> returnLists;
int end;
while (cloneList.size() > 0)
{
end = cloneList.lastIndexOf(cloneList.get(0));
returnLists.add(cloneList.subList(0, end));
cloneList.removeAll(cloneList.subList(0, end));
}
return returnList.toArray();
}