46

I've got a HashSet<Integer> with a bunch of Integers in it. I want to turn it into an array, but calling

hashset.toArray();

returns an Object[]. Is there a better way to cast it to an array of int other than iterating through every element manually? I want to pass the array to

void doSomething(int[] arr)

which won't accept the Object[] array, even if I try casting it like

doSomething((int[]) hashSet.toArray());
Jeffrey Bosboom
  • 13,313
  • 16
  • 79
  • 92
jackbot
  • 2,931
  • 3
  • 27
  • 35

8 Answers8

39

You can create an int[] from any Collection<Integer> (including a HashSet<Integer>) using Java 8 streams:

int[] array = coll.stream().mapToInt(Number::intValue).toArray();

The library is still iterating over the collection (or other stream source) on your behalf, of course.

In addition to being concise and having no external library dependencies, streams also let you go parallel if you have a really big collection to copy.

Jeffrey Bosboom
  • 13,313
  • 16
  • 79
  • 92
22

Apache's ArrayUtils has this (it still iterates behind the scenes):

doSomething(ArrayUtils.toPrimitive(hashset.toArray()));

They're always a good place to check for things like this.

Dwhitz
  • 1,250
  • 7
  • 26
  • 38
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
  • 3
    Automatic +1 for recommending Apache Commons. – skaffman Mar 15 '10 at 23:41
  • @skaffman I'd recommend Apache Commons Lang ... not for this particular problem though ... but anyway, make your move ;) – sfussenegger Mar 15 '10 at 23:51
  • 1
    Actually, it doesn't iterate behind the scenes - it iterates twice. There is an unnecessary `Integer[]` that slows down the process of creating a primitive array from a collection. Actually, I think the choice to use `Integer[]` as parameter for `toPrimitive(..)` instead of `Iterable` is a bit clunky as `Arrays.asList(Integer[])` is a much faster operation than `collection.toArray()`. Hence I won't automatically +1 for recommending apache commons :) – sfussenegger Mar 16 '10 at 00:06
  • sfussenegger, Apache Commons (what I meant by "it") only iterates once. You're right that the creation of the array requires an iteration. – Matthew Flaschen Mar 16 '10 at 00:31
  • I though so but still wanted to emphasize it (the -1 wasn't from me btw) – sfussenegger Mar 16 '10 at 00:46
  • I can only get this to work if I use `ArrayUtils.toPrimitive(hashset.toArray( new Integer[hashset.size()]))` – Jason B. Apr 21 '17 at 21:36
  • 2
    @sfussenegger actually, the code as written in the answer produces an `Object[]`, so it doesn’t even work. You would need `ArrayUtils.toPrimitive(hashset.toArray(new Integer[0]))`, to make it the inefficient solution that it is supposed to be. – Holger Jan 29 '19 at 16:59
9

Try this. Using java 8.

    Set<Integer> set = new HashSet<>();
    set.add(43);
    set.add(423);
    set.add(11);
    set.add(44);
    set.add(56);
    set.add(422);
    set.add(34);
    int[] arr = set.stream().mapToInt(Integer::intValue).toArray();
sameer
  • 91
  • 1
  • 3
8

You can convert a Set<Integer> to Integer[] even without Apache Utils:

Set<Integer> myset = new HashSet<Integer>();
Integer[] array = myset.toArray(new Integer[0]);

However, if you need int[] you have to iterate over the set.

Floern
  • 33,559
  • 24
  • 104
  • 119
Tombart
  • 30,520
  • 16
  • 123
  • 136
5

Note: This answer is outdated, use Stream.mapToInt(..)

public int[] toInt(Set<Integer> set) {
  int[] a = new int[set.size()];
  int i = 0;
  for (Integer val : set) {
    // treat null as 0
    a[i++] = val == null ? 0 : val;
  }
  return a;
}

Now that I wrote the code for you it's not that manual anymore, is it? ;)

sfussenegger
  • 35,575
  • 15
  • 95
  • 119
  • 5
    It wasn't that writing the code to do it manually was a problem, I was just curious to see if there was a better way to do it. – jackbot Mar 15 '10 at 23:44
  • Well, the essence of my answer was that the only way to avoid writing this code is getting others to write it (but actually that's the case for just about any code) - which you successfully did ;) – sfussenegger Mar 15 '10 at 23:48
  • Can you put null in a Set? If so, this code will NPE. I'm not sure what the original poster would want to do with nulls though. I guess omit them from the resulting array. – davidsheldon Oct 14 '10 at 06:53
  • @davidsheldon Valid remark. You may put null into a Set if the implementation supports it (obviously, yes, but that's what Set's Javadoc defines). HashSet and TreeMap will throw a NPE when trying to add null. Throwing a NPE in case set contains null seems to be the way to go though, of course along with appropriate documentation of this behavior - we all document thoroughly, don't we ;) – sfussenegger Oct 14 '10 at 11:21
  • Not quiet correct. `HashSet` allows `null` and `TreeSet` will allow `null` if a custom `Comparator` which can deal with `null` has been specified. But it’s true that the best behavior is to just let the code throw a `NullPointerException` if the set contains `null`. – Holger Jan 29 '19 at 17:32
4

You can just use Guava's:

Ints.toArray(Collection<? extends Number> collection)
2

Nope; you've got to iterate over them. Sorry.

Carl Manaster
  • 39,912
  • 17
  • 102
  • 155
  • It makes sense if you think about it. ints aren't objects, so typecasting one to the other doesn't work. – Brendan Long Mar 15 '10 at 23:35
  • 1
    It seems odd that you can't get an array of ints from a HashSet of Integers though, shouldn't the autoboxing kick in and allow you to do it? It's not like the HashSet contains a mixture of types, they're all Integers so (as far as I can see), it wouldn't be a problem. – jackbot Mar 15 '10 at 23:46
  • 2
    Collections can only hold objects (Integers in your case). Thus, it would be odd to have a special method to get an array of ints (corresponding methods would be required for other primitive types). Auto-boxing doesn't help, because that only applies for a single primitive<->object conversion. Keep in mind that the actual class (due to type erasure) is HashSet, not HashSet (only a compile-time concept). – Matthew Flaschen Mar 16 '10 at 00:13
  • @MatthewFlaschen wouldn't type erasure cause the actual class to be HashSet? -http://docs.oracle.com/javase/tutorial/java/generics/erasure.html – committedandroider Feb 20 '15 at 04:41
-4

You could also use the toArray(T[] contents) variant of the toArray() method. Create an empty array of ints of the same size as the HashSet, and then pass it to the toArray() method:

Integer[] myarray = new Integer[hashset.size()];
doSomething(hashset.toArray(myarray));

You'd have to change the doSomething() function to accept an Integer[] array instead of int[]. If that is not feasible, you'd have convert the array of values returned by toArray to int[].

Shiprack
  • 1,095
  • 11
  • 18
  • It would help to provide your compile errors so I can tell what's wrong with my code. – Shiprack Aug 07 '12 at 12:12
  • 2
    Why don't you just try compiling it yourself? Once you see the compile error, I can explain you why it happened. – jkff Aug 07 '12 at 19:49