Creating Short [] Threads

Based on a Population list with a continuous range of shorts I tried to create an array of primitive shorts. It turned out to be surprisingly harder than expected.

Short[] range = IntStream.range(0, 500).mapToObj(value -> (short) value).toArray(Short[]::new) worked, but:

Short[] range = IntStream.range(0, 500).mapToObj(value -> (short) value).toArray(Short[]::new) a compiler error was generated:

 method toArray in interface Stream<T> cannot be applied to given types; required: IntFunction<A[]> found: short[]::new reason: inference variable A has incompatible bounds equality constraints: short upper bounds: Object where A,T are type-variables: A extends Object declared in method <A>toArray(IntFunction<A[]>) T extends Object declared in interface Stream 

This seems to be the intersection of two issues:

  • API primitive flows API does not provide an implementation for short s.
  • The non-primitive Stream APIs do not seem to provide a mechanism for returning a primitive array.

Any ideas?

+5
source share
2 answers

You can use my StreamEx library. It extends standand threads with additional methods. One of the goals of my library is to better interact with old code. In particular, it has IntStreamEx.toShortArray() and IntStreamEx.of(short...) :

 short[] numbers = IntStreamEx.range(500).toShortArray(); short[] evenNumbers = IntStreamEx.of(numbers).map(x -> x*2).toShortArray(); 

Note that this is still a stream of int numbers. When toShortArray() called, they are automatically converted to short using the (short) cast operation, so overflow is possible. Therefore use with caution.

There are also IntStreamEx.toByteArray() , IntStreamEx.toCharArray() and DoubleStreamEx.toFloatArray() .

+1
source

The canonical method will implement a custom Collector .

 class ShortCollector { public static Collector<Integer,ShortCollector,short[]> TO_ARRAY =Collector.of(ShortCollector::new, ShortCollector::add, ShortCollector::merge, c->c.get()); short[] array=new short[100]; int pos; public void add(int value) { int ix=pos; if(ix==array.length) array=Arrays.copyOf(array, ix*2); array[ix]=(short)value; pos=ix+1; } public ShortCollector merge(ShortCollector c) { int ix=pos, cIx=c.pos, newSize=ix+cIx; if(array.length<newSize) array=Arrays.copyOf(array, newSize); System.arraycopy(c.array, 0, array, ix, cIx); return this; } public short[] get() { return pos==array.length? array: Arrays.copyOf(array, pos); } } 

Then you can use it as

 short[] array=IntStream.range(0, 500).boxed().collect(ShortCollector.TO_ARRAY); 

The disadvantage is that Collector works only for reference types (since Generics does not support primitive types), so you need to resort to boxed() , and collectors cannot use information about the number of elements (if they are ever available). Thus, performance will be much worse than toArray() in a primitive data stream.

So, a solution aimed at increasing productivity (I limit this for a single-threaded case) will look like this:

 public static short[] toShortArray(IntStream is) { Spliterator.OfInt sp = is.spliterator(); long l=sp.getExactSizeIfKnown(); if(l>=0) { if(l>Integer.MAX_VALUE) throw new OutOfMemoryError(); short[] array=new short[(int)l]; sp.forEachRemaining(new IntConsumer() { int ix; public void accept(int value) { array[ix++]=(short)value; } }); return array; } final class ShortCollector implements IntConsumer { int bufIx, currIx, total; short[][] buffer=new short[25][]; short[] current=buffer[0]=new short[64]; public void accept(int value) { int ix = currIx; if(ix==current.length) { current=buffer[++bufIx]=new short[ix*2]; total+=ix; ix=0; } current[ix]=(short)value; currIx=ix+1; } short[] toArray() { if(bufIx==0) return currIx==current.length? current: Arrays.copyOf(current, currIx); int p=0; short[][] buf=buffer; short[] result=new short[total+currIx]; for(int bIx=0, e=bufIx, l=buf[0].length; bIx<e; bIx++, p+=l, l+=l) System.arraycopy(buf[bIx], 0, result, p, l); System.arraycopy(current, 0, result, p, currIx); return result; } } ShortCollector c=new ShortCollector(); sp.forEachRemaining(c); return c.toArray(); } 

You can use it as

 short[] array=toShortArray(IntStream.range(0, 500)); 
0
source

All Articles