184

配列のセグメントを返すJavaのメソッドを探しています。例として、バイト配列の4番目と5番目のバイトを含むバイト配列を取得します。そのためだけに、ヒープメモリに新しいバイト配列を作成する必要はありません。現在、次のコードがあります。

doSomethingWithTwoBytes(byte[] twoByteArray);

void someMethod(byte[] bigArray)
{
      byte[] x = {bigArray[4], bigArray[5]};
      doSomethingWithTwoBytes(x);
}

doSomething(bigArray.getSubArray(4, 2))たとえば、4がオフセットで、2が長さである場合に実行する方法があるかどうかを知りたいです。

4

15 に答える 15

186

免責事項:この回答は質問の制約に準拠していません:

それを行うためだけに、ヒープメモリに新しいバイト配列を作成する必要はありません。

(正直なところ、私の回答は削除する価値があると感じています。@unique72 の回答は正しいです。この編集をしばらく放置してから、この回答を削除します。 )


追加のヒープ割り当てなしで配列でこれを直接行う方法はわかりませんが、サブリストラッパーを使用した他の回答には、ラッパーのみに追加の割り当てがありますが、配列には割り当てられません。大きな配列。

とは言っても、簡潔さを求めるなら、ユーティリティー・メソッドArrays.copyOfRange()は Java 6 (2006 年後半?) で導入されました。

byte [] a = new byte [] {0, 1, 2, 3, 4, 5, 6, 7};

// get a[4], a[5]

byte [] subArray = Arrays.copyOfRange(a, 4, 6);
于 2009-07-08T21:53:07.173 に答える
172

Arrays.asList(myArray)new に委任しArrayList(myArray)ます。これは、配列をコピーせず、参照を格納するだけです。List.subList(start, end)その後に使用するSubListと、元のリストを参照するだけの a が作成されます (これはまだ配列を参照するだけです)。配列またはその内容のコピーはなく、ラッパーの作成のみであり、関連するすべてのリストは元の配列によってサポートされます。(もっと重いと思っていました。)

于 2011-01-11T05:41:28.347 に答える
39

スペースを割り当ててデータをコピーする必要さえないように、ポインター スタイルのエイリアシング アプローチを探している場合は、運が悪いと思います。

System.arraycopy() ソースから宛先にコピーし、このユーティリティの効率が主張されています。宛先配列を割り当てる必要があります。

于 2009-07-08T20:35:25.923 に答える
23

1つの方法は、配列をラップしjava.nio.ByteBuffer、絶対put / get関数を使用し、バッファーをスライスしてサブ配列で機能することです。

例えば:

doSomething(ByteBuffer twoBytes) {
    byte b1 = twoBytes.get(0);
    byte b2 = twoBytes.get(1);
    ...
}

void someMethod(byte[] bigArray) {
      int offset = 4;
      int length = 2;
      doSomething(ByteBuffer.wrap(bigArray, offset, length).slice());
}

wrap()との両方を呼び出す必要があることに注意してください。これはslice()wrap()それ自体が相対的なput / get関数にのみ影響し、絶対関数には影響しないためです。

ByteBuffer理解するのは少し難しいかもしれませんが、おそらく効率的に実装されており、学ぶ価値があります。

于 2011-11-08T17:49:38.893 に答える
20

java.nio.Bufferを使用します。これは、さまざまなプリミティブ型のバッファー用の軽量ラッパーであり、スライス、位置、変換、バイト順序などの管理に役立ちます。

バイトがストリームから発信されている場合、NIOバッファーは、ネイティブリソースに基づくバッファーを作成する「ダイレクトモード」を使用できます。これにより、多くの場合、パフォーマンスを向上させることができます。

于 2009-07-08T20:52:03.830 に答える
14

ApachecommonsでArrayUtils.subarrayを使用できます。完璧ではありませんが、欠点よりも少し直感的ですSystem.arraycopy. 。それは、コードに別の依存関係を導入することです。

于 2009-07-08T20:42:13.383 に答える
10

サブリストの回答は既にここにありますが、これがコピーではなく真のサブリストであることを示すコードは次のとおりです。

public class SubListTest extends TestCase {
    public void testSubarray() throws Exception {
        Integer[] array = {1, 2, 3, 4, 5};
        List<Integer> list = Arrays.asList(array);
        List<Integer> subList = list.subList(2, 4);
        assertEquals(2, subList.size());
        assertEquals((Integer) 3, subList.get(0));
        list.set(2, 7);
        assertEquals((Integer) 7, subList.get(0));
    }
}

ただし、これを配列で直接行う良い方法があるとは思いません。

于 2009-07-08T20:40:28.987 に答える
9
List.subList(int startIndex, int endIndex)
于 2009-07-08T20:31:27.617 に答える
7

を使用すると、何かを透過的Listに使用および操作できます。subListプリミティブ配列では、ある種のオフセット (制限) を追跡する必要があります。ByteBuffer私が聞いたのと同様のオプションがあります。

編集: 便利なメソッドを担当している場合は、境界で定義するだけで済みます(Java自体の多くの配列関連メソッドで行われているように:

doUseful(byte[] arr, int start, int len) {
    // implementation here
}
doUseful(byte[] arr) {
    doUseful(arr, 0, arr.length);
}

ただし、配列要素自体を操作する場合、たとえば、何かを計算して結果を書き戻す場合は明確ではありません。

于 2009-07-08T20:33:13.620 に答える
6

1つのオプションは、配列全体と開始インデックスと終了インデックスを渡し、渡された配列全体を反復処理するのではなく、それらの間で反復処理することです。

void method1(byte[] array) {
    method2(array,4,5);
}
void method2(byte[] smallarray,int start,int end) {
    for ( int i = start; i <= end; i++ ) {
        ....
    }
}
于 2009-07-08T20:44:40.790 に答える
2

@unique72 シンプルな関数または行として答えます。オブジェクトを「スライス」するそれぞれのクラスタイプに置き換える必要がある場合があります。さまざまなニーズに合わせて 2 つのバリエーションが用意されています。

/// Extract out array from starting position onwards
public static Object[] sliceArray( Object[] inArr, int startPos ) {
    return Arrays.asList(inArr).subList(startPos, inArr.length).toArray();
}

/// Extract out array from starting position to ending position
public static Object[] sliceArray( Object[] inArr, int startPos, int endPos ) {
    return Arrays.asList(inArr).subList(startPos, endPos).toArray();
}
于 2015-02-07T08:52:44.197 に答える
1

薄いListラッパーはどうですか?

List<Byte> getSubArrayList(byte[] array, int offset, int size) {
   return new AbstractList<Byte>() {
      Byte get(int index) {
         if (index < 0 || index >= size) 
           throw new IndexOutOfBoundsException();
         return array[offset+index];
      }
      int size() {
         return size;
      }
   };
}

(未テスト)

于 2011-01-14T14:34:49.120 に答える
1

配列の最後まで繰り返す必要があり、配列をコピーしたくありませんでした。私のアプローチは、配列に対して Iterable を作成することでした。

public static Iterable<String> sliceArray(final String[] array, 
                                          final int start) {
  return new Iterable<String>() {
    String[] values = array;
    int posn = start;

    @Override
    public Iterator<String> iterator() {
      return new Iterator<String>() {
        @Override
        public boolean hasNext() {
          return posn < values.length;
        }

        @Override
        public String next() {
          return values[posn++];
        }

        @Override
        public void remove() {
          throw new UnsupportedOperationException("No remove");
        }
      };
    }
  };
}
于 2016-06-27T02:58:36.013 に答える