使用流生成short [] [英] Generating a short[] using streams

查看:116
本文介绍了使用流生成short []的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用连续的短裤范围填充列表的基础上,我尝试生成一系列原始短片。事实证明这比预期的要难得多。



Short [] range = IntStream.range(0,500).mapToObj(value - > ;(短)值).toArray(短[] ::新)工作但是:



short [] range = IntStream.range(0,500).mapToObj(value - >(short)value)。toArray(short [] :: new)生成编译器错误:

 接口Stream< T>中的方法toArray不能适用于给定的类型;需要
:IntFunction< A []>找到
:short [] :: new
原因:推理变量A具有不兼容的边界
等式约束:short
上限:对象
其中A,T是类型-variables:
扩展在方法< A>中声明的对象toArray(IntFunction< A []>)
T扩展在接口Stream
<中声明的对象/ pre>

这似乎是两个问题的交集:


  1. 原始Stream API不提供 short 的实现。

  2. 非原始Stream API似乎不提供机制返回原始数组。

任何想法?

解决方案

规范方式是实现自定义收集器

  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] =(短)值;
pos = ix + 1;
}
公共ShortCollector合并(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);
返回此;
}
public short [] get(){
return pos == array.length? array:Arrays.copyOf(array,pos);
}
}

然后你可以像

$一样使用它b
$ b

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

缺点是收藏家只能工作对于引用类型(因为Generics不支持基本类型),因此您必须求助 boxed()并且收集器不能使用有关元素数量的信息(如果永远可用)。因此,在原始数据流上,性能可能远远低于 toArray()



所以,争取更高性能的解决方案(我将其限制为单线程情况)将如下所示:

  public static short [] toShortArray(IntStream is){
Spliterator.OfInt sp = is.spliterator();
long l = sp.getExactSizeIfKnown();
if(l> = 0){
if(l> Integer.MAX_VALUE)抛出新的OutOfMemoryError();
short [] array = new short [(int)l];
sp.forEachRemaining(new IntConsumer(){
int ix;
public void accept(int value){
array [ix ++] =(short)value;
}
});
返回数组;
}
final class ShortCollector实现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];
总计+ = ix;
ix = 0;
}
当前[ix] =(短)值;
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,结果,p,l);
System.arraycopy(current,0,result,p,currIx);
返回结果;
}
}
ShortCollector c = new ShortCollector();
sp.forEachRemaining(c);
返回c.toArray();
}

您可以像


$ b $一样使用它b

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


Building upon Populating a List with a contiguous range of shorts I tried generating an array of primitive shorts. This 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) generated a compiler error:

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 an intersection of two problems:

  1. The primitive Stream APIs do not provide an implementation for shorts.
  2. The non-primitive Stream APIs do not seem to provide a mechanism to return a primitive array.

Any ideas?

解决方案

The canonical way would be implementing 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 could use it like

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

The drawback is that Collectors only work for reference types (as Generics doesn’t support primitive types), thus you have to resort to boxed() and collectors can’t utilize information about the number of elements (if ever available). Thus, the performance is likely to be far worse than toArray() on a primitive data stream.

So, a solution striving for higher performance (I limit this to the 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 may use it like

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

这篇关于使用流生成short []的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆