web-dev-qa-db-ja.com

配列をX長さの断片に分割

現在、サイズNの配列があります。配列からXバイトごとにコピーしようとしています。

配列のサイズが10でサイズ3の配列が必要な場合の例最初の3つの要素をコピーし、次に次の3つ、最後の1つをコピーします。

現在、私は次のアルゴリズムを使用しています:

int I = 0;
int sub = bytes.length;
int counter = 0;
for (I = 0; I < bytes.length; ++I) {
    if (I % 3 == 0 && I != 0) {
       NewArray[counter] = Arrays.copyOfRange(bytes, I - 3, I));
        sub -= 3;
        ++counter;
    }
}

NewArray[counter] = Arrays.copyOfRange(bytes, I - sub, I)); //Copy remainder.

私が望むことを行うためのより効率的なまたはより適切な方法はありますか?このアルゴリズムはかなり悪く見えます= l

どのようにしてそれを改善できるか、または少なくともヒントはありますか?

12
Brandon

これはどうですか:

int x = 3;  // chunk size
int len = bytes.length;
int counter = 0;

for (int i = 0; i < len - x + 1; i += x)
    newArray[counter++] = Arrays.copyOfRange(bytes, i, i + x);

if (len % x != 0)
    newArray[counter] = Arrays.copyOfRange(bytes, len - len % x, len);
10
arshajii

これが便利な方法で、byte[]byte[]の配列に変換します。したがって、結果はbyte[][]です。

public byte[][] splitBytes(final byte[] data, final int chunkSize)
{
  final int length = data.length;
  final byte[][] dest = new byte[(length + chunkSize - 1)/chunkSize][];
  int destIndex = 0;
  int stopIndex = 0;

  for (int startIndex = 0; startIndex + chunkSize <= length; startIndex += chunkSize)
  {
    stopIndex += chunkSize;
    dest[destIndex++] = Arrays.copyOfRange(data, startIndex, stopIndex);
  }

  if (stopIndex < length)
    dest[destIndex] = Arrays.copyOfRange(data, stopIndex, length);

  return dest;
}

以前と比較したいくつかの利点ベストアンサー

  1. for条件は、<=よりも意味のある< ... + 1を使用します。
  2. Stop-indexを一時フィールドに入れると、最後のifブロックの計算回数が減ります。

(ユニットテスト済み)

7
bvdb

ここでやることはほとんどありません:

まず、一般的な慣習では、大文字を使用して変数名を開始することを避け、IおよびNewArray変数をそれぞれ「i」および「newArray」に変更します。

次に、ループを初めて実行するときにi-3がIndexOutOfBounds例外につながるため、コードは機能しません。

最後に、newArray配列のサイズの設定方法は示していません。

int sublen = 3; // how many elements in each sub array.
int size = ((bytes.length - 1) / sublen) + 1; // how many newArray members we will need
byte[][] newArray = new byte[size][]; 
int to = byte.length;
int cursor = size - 1;
int from = cursor * sublen;
while (cursor >= 0) {
    newArray[cursor] = Arrays.copyOfRange(bytes, from, to);
    to = from;
    from -= sublen;
    cursor --;
}
3
rolfl

これが私の実装です。あなたが決めた最大サイズまでのサブ配列に配列を分割し、サブ配列を配列のリストに入れます。配列のサイズが選択した最大サイズの倍数でない場合、最後の配列は小さくなります。

import Java.util.Arrays;
...

public static <T> List<T[]> splitArray(T[] items, int maxSubArraySize) {
  List<T[]> result = new ArrayList<T[]>();
  if (items ==null || items.length == 0) {
      return result;
  }

  int from = 0;
  int to = 0;
  int slicedItems = 0;
  while (slicedItems < items.length) {
      to = from + Math.min(maxSubArraySize, items.length - to);
      T[] slice = Arrays.copyOfRange(items, from, to);
      result.add(slice);
      slicedItems += slice.length;
      from = to;
  }
  return result;
}
2
Gubatron

特別な正規表現でsplitを使用できます。

 System.out.println(Arrays.toString(
     "Thisismystringiwanttosplitintogroupswith4chareach".split("(?<=\\G.{4})")
 ));

Alan Mooreによる 以前の投稿 へのクレジット。ご覧になって投票してください。

0
henderso
import Java.util.Arrays;

public class Test {

    private void run() {
        try {

            byte[] cfsObjIds = "abcdefghij".getBytes();
            System.out.println(Arrays.toString(cfsObjIds));

            final int chunkSize = 4;
            System.out.println("Split by " + chunkSize + ":");
            int objQty = cfsObjIds.length;
            for (int i = 0; i < objQty; i += chunkSize) {
                int chunkUpperLimit = Math.min(objQty, i + chunkSize);
                byte[] cfsIdsChunk = Arrays.copyOfRange(cfsObjIds, i, chunkUpperLimit);

                System.out.println(Arrays.toString(cfsIdsChunk));
            }

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        new Test().run();
    }
}
0
Splash

私はこの質問がかなり古いことを知っていますが、ねえ、誰かが別のきれいなJavaこの一般的な質問の答えを探すことができます。あなたはリスト(Java 7)で作業しています)、かなりシンプルでリストの一部を取得するクリーンメソッド: List.subList(fromIndex、toIndex)

使い方は簡単です。質問の例をとると、次のようになります。

int chunkSize = 3;
int counter = 0;
// bytes must be a List like an ArrayList
List<Byte> byteList = Arrays.asList(bytes);
int length = byteList.size(); 
for (int fromIndex = 0; fromIndex < length; fromIndex += chunkSize) {
   int toIndex = fromIndex + chunkSize;
   if(toIndex > length){
      toIndex = length;
   }
   NewArray[counter] = byteList.subList(fromIndex, toIndex);
   counter++;
}
// Now NewArray[] contain sub array and the last one is of the remaining length

「カウンター」に乗るために、 List アプローチのNewArrayのビルド方法を変更する人もいます。

// NewArray must be a List<List<Byte>>
NewArray.addAll(byteList.subList(fromIndex, toIndex));

これが将来誰かを助けることを願っています!

0
CtrlX

これは配列を分割する関数です。以下のmainメソッドを使用してテストできます。

private static List<Integer[]> splitArray(Integer[] originalArray, int chunkSize) {
List<Integer[]> listOfArrays = new ArrayList<Integer[]>();
int totalSize = originalArray.length;
if(totalSize < chunkSize ){
   chunkSize = totalSize;
}
int from = 0;
int to = chunkSize;

while(from < totalSize){
    Integer[] partArray = Arrays.copyOfRange(originalArray, from, to);
    listOfArrays.add(partArray);

    from+= chunkSize;
    to = from + chunkSize;
    if(to>totalSize){
        to = totalSize;
    }
}
return listOfArrays;
}

試験方法:

public static void main(String[] args) {
List<Integer> testingOriginalList = new ArrayList<Integer>();

for(int i=0;i<200;i++){
    testingOriginalList.add(i);
}

int batchSize = 51;
Integer[] originalArray = testingOriginalList.toArray(new Integer[]{});

List<Integer[]> listOfArrays = splitArray(originalArray, batchSize);


for(Integer[] array : listOfArrays){
    System.out.print(array.length + ", ");
    System.out.println(Arrays.toString(array));
}
}
0
Evan Hu

実際に非常に大きなチャンクが必要で、その内容を個別に変更したくない場合は、ByteBuffer.wrap()を使用して同じ初期配列を再利用し、次にslice()を繰り返し使用することを検討してください。これにより、不要なコピーやメモリの浪費を防ぐことができます。

0
leventov