繁体   English   中英

如何从迭代器中获取int []?

[英]How can I get an int[] out of an Iterator?

我有一个相当于Iterator<Integer> ……实际上,它是一个class Thing ,它接受Visitor<SomeObject>并为其中包含的SomeObject的子集调用visit() ,因此我必须实现Visitor<SomeObject>它做这样的事情:

// somehow get all the Id's from each of the SomeObject that Thing lets me visit
public int[] myIdExtractor(Thing thing)
{
    SomeCollection c = new SomeCollection();
    thing.visitObjects(new Visitor<SomeObject>()
         {
              public void visit(SomeObject obj) { c.add(obj.getId()); }
         }
    );
    return convertToPrimitiveArray(c);
}

我需要提取一个包含结果的int[] ,但我不确定该对SomeCollectionconvertToPrimitiveArray使用什么。 结果数量是未知的,并且将会很大(10K-500K)。 有什么比使用ArrayList<Integer>进行SomeCollection更好的选择SomeCollection

public int[] convertToPrimitiveArray(List<Integer> ints)
{
    int N = ints.size();
    int[] array = new int[N];
    int j = 0;
    for (Integer i : ints)
    {
        array[j++] = i;
    }
    return array;
}

效率和内存使用情况令人担忧。

提出一个将int收集到数组中的类并不是很难(即使您没有使用为您完成此工作的库)。

public class IntBuffer {
    private int[] values = new int[10];
    private int size = 0;
    public void add(int value) {
        if (!(size < values.length)) {
            values = java.util.Arrays.copyOf(values, values.length*2);
        }
        values[size++] = value;
    }
    public int[] toArray() {
        return java.util.Arrays.copyOf(values, size);
    }
}

(免责声明:这是stackoverflow,我什至没有尝试编译此代码。)

或者,您可以使用DataOutputStreamint存储在ByteArrayOutputStream

final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
final DataOutputStream out = new DataOutputStream(byteOut);
...
    out.writeInt(value);
...
out.flush();
final byte[] bytes = byteOut.toByteArray();
final int[] ints = new int[bytes.length/4];
final ByteArrayInputStream byteIn = new ByteArrayInputStream(bytes);
final DataInputStream in = new DataOutputStream(byteIn);
for (int ct=0; ct<ints.length; ++ct) {
    ints[ct] = in.readInt();
}

(免责声明:这是stackoverflow,我什至没有尝试编译此代码。)

您可以看一下pjc之类的东西来处理此问题。 那是为原语制作的集合框架。

为了进行基准测试,我使用LFSR生成器组合了一个测试程序,以防止编译器优化测试数组。 无法下载pjc,但我认为计时应该类似于Tom的IntBuffer类,到目前为止,它是赢家。 ByteArrayOutputStream方法的速度与我原来的ArrayList<Integer>方法相同。 我在3GHz奔腾4上运行J2SE 6u13,并具有大约2 20个值,在JIT运行其过程之后,IntBuffer方法大约比使用“健忘”的参考实现花费大约40毫秒(每项仅40毫秒!)。集合仅存储visit()的最后一个参数(因此编译器不会对其进行优化)。 其他两种方法大约需要300毫秒,大约是慢速的8倍。

编辑:我怀疑流方法的问题是存在潜在的我不得不捕捉的不确定性。

(对于参数,请运行PrimitiveArrayTest 1 2)

package com.example.test.collections;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class PrimitiveArrayTest {
    interface SomeObject {
        public int getX();
    }
    interface Visitor {
        public void visit(SomeObject obj);
    }

    public static class PlainObject implements SomeObject
    {
        private int x;
        public int getX() { return this.x; }
        public void setX(int x) { this.x = x; }  
    }

    public static class Thing
    {
        /* here's a LFSR        
         * see http://en.wikipedia.org/wiki/Linear_feedback_shift_register
         * and http://www.ece.cmu.edu/~koopman/lfsr/index.html
         */
        private int state;
        final static private int MASK = 0x80004;
        private void _next()
        {
            this.state = (this.state >>> 1) 
            ^ (-(this.state & 1) & MASK);
        }
        public Thing(int state) { this.state = state; }     
        public void setState(int state) { this.state = state; }

        public void inviteVisitor(Visitor v, int terminationPoint)
        {
            PlainObject obj = new PlainObject();
            while (this.state != terminationPoint)
            {
                obj.setX(this.state);
                v.visit(obj);
                _next();
            }
        }
    }

    static public abstract class Collector implements Visitor
    {
        abstract public void initCollection();
        abstract public int[] getCollection();
        public int[] extractX(Thing thing, int startState, int endState)
        {
            initCollection();
            thing.setState(startState);
            thing.inviteVisitor(this, endState);
            return getCollection();
        }
        public void doit(Thing thing, int startState, int endState)
        {
            System.out.printf("%s.doit(thing,%d,%d):\n",
                    getClass().getName(),
                    startState,
                    endState);
            long l1 = System.nanoTime();
            int[] result = extractX(thing,startState,endState);
            long l2 = System.nanoTime();
            StringBuilder sb = new StringBuilder();
            sb.append(String.format("%d values calculated in %.4f msec ",
                    result.length, (l2-l1)*1e-6));
            int N = 3;
            if (result.length <= 2*N)
            {
                sb.append("[");
                for (int i = 0; i < result.length; ++i)
                {
                    if (i > 0)
                        sb.append(", ");
                    sb.append(result[i]);
                }
                sb.append("]");
            }
            else
            {
                int sz = result.length;
                sb.append(String.format("[%d, %d, %d... %d, %d, %d]",
                        result[0], result[1], result[2], 
                        result[sz-3], result[sz-2], result[sz-1]));
            }
            System.out.println(sb.toString());          
        }
    }

    static public class Collector0 extends Collector
    {
        int lastint = 0;
        @Override public int[] getCollection() { return new int[]{lastint}; }
        @Override public void initCollection() {}
        @Override public void visit(SomeObject obj) {lastint = obj.getX(); }
    }
    static public class Collector1 extends Collector
    {
        final private List<Integer> ints = new ArrayList<Integer>();

        @Override public int[] getCollection() {
            int N = this.ints.size();
            int[] array = new int[N];
            int j = 0;
            for (Integer i : this.ints)
            {
                array[j++] = i;
            }
            return array;           
        }
        @Override public void initCollection() { }
        @Override public void visit(SomeObject obj) { ints.add(obj.getX()); }
    }

    static public class Collector2 extends Collector
    {
        /*
         * adapted from http://stackoverflow.com/questions/1167060
         * by Tom Hawtin
         */
        private int[] values;
        private int size = 0;
        @Override public void visit(SomeObject obj) { add(obj.getX()); }
        @Override public void initCollection() { values = new int[32]; }
        private void add(int value) {
            if (!(this.size < this.values.length)) {
                this.values = java.util.Arrays.copyOf(
                        this.values, this.values.length*2);
            }
            this.values[this.size++] = value;
        }
        @Override public int[] getCollection() {
            return java.util.Arrays.copyOf(this.values, this.size);
        }       
    }

    static public class Collector3 extends Collector
    {
        /*
         * adapted from http://stackoverflow.com/questions/1167060
         * by Tom Hawtin
         */
        final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        final DataOutputStream out = new DataOutputStream(this.byteOut);
        int size = 0;
        @Override public int[] getCollection()  {
            try
            {
                this.out.flush();
                final int[] ints = new int[this.size];
                final ByteArrayInputStream byteIn 
                    = new ByteArrayInputStream(this.byteOut.toByteArray());
                final DataInputStream in = new DataInputStream(byteIn);

                for (int ct=0; ct<ints.length; ++ct) {
                    ints[ct] = in.readInt();
                }
                return ints;
            }
            catch (IOException e) { /* gulp */ }

            return new int[0]; // failure!?!??!
        }

        @Override public void initCollection() { }
        @Override public void visit(SomeObject obj) {
            try {
                this.out.writeInt(obj.getX());
                ++this.size;
            }
            catch (IOException e) { /* gulp */ }
        }       
    }
    public static void main(String args[])
    {
        int startState = Integer.parseInt(args[0]);
        int endState = Integer.parseInt(args[1]);
        Thing thing = new Thing(0);
        // let JIT do its thing
        for (int i = 0; i < 20; ++i)
        {
            Collector[] collectors = {new Collector0(), new Collector1(), new Collector2(), new Collector3()};
            for (Collector c : collectors)
            {
                c.doit(thing, startState, endState);
            }
            System.out.println();
        }
    }
}

可以使用List.toArray(T [] a)来代替convertToPrimitiveArray:

ArrayList<int> al = new ArrayList<int>();
// populate al
int[] values = new int[al.size()];
al.toArray(values);

出于其他方面的考虑,LinkedList可能比ArrayList更好,因为您事先不知道结果集的大小。

如果性能确实是一个问题,那么最好自己动手int [],并在每次增长时都使用System.arraycopy()。 将任何集合所需的从int到Integer的装箱/拆箱操作可能会受到伤害。

当然,与任何与性能相关的问题一样,在花费太多时间进行优化之前,请测试并确保它确实很重要。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM