【问题标题】:Split array into pieces of X length将数组拆分为 X 长度的片段
【发布时间】:2013-10-14 18:23:20
【问题描述】:

目前我有一个大小为 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

任何想法我可以如何改进它或至少一个提示?

【问题讨论】:

    标签: java arrays performance algorithm


    【解决方案1】:

    这个呢:

    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);
    

    【讨论】:

    • 将为 byte.length % 3 == 0 的所有情况生成一个长度为 0 的数组,并将导致最后一次迭代的 ArrayIndexOutOfBounds ......当 i+x > bytes.length .. ...
    • 修复了 len % 3 == 0 的情况,但在 i+x > bytes.length 的 2/3 情况下,您仍然会有无效数据(取决于字节数据类型可能会添加额外的(byte)0
    • @rolfl 现在应该真的修复了。我在循环条件中需要一个+ 1
    • newArray[counter++] 是什么意思?
    【解决方案2】:

    您可以将 split 与特殊的正则表达式一起使用:

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

    感谢艾伦·摩尔的earlier post。请访问并投票。

    【讨论】:

    • 如果您已经在使用字符串或数组很小,这没关系。对于大字节数组,在字符串和正则表达式之间进行转换有点矫枉过正。
    【解决方案3】:

    这里有几件事要做:

    首先,常见约定不赞成使用大写字母开头的变量名,将INewArray 变量分别更改为“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 --;
    }
    

    【讨论】:

      【解决方案4】:

      如果您实际上需要相当大的块,并且不想单独修改它们的内容,请考虑通过ByteBuffer.wrap()slice() 重复使用相同的初始数组。这样可以防止不必要的复制和内存浪费。

      【讨论】:

        【解决方案5】:

        这是我的实现,它将您的数组拆分为您决定的最大大小的子数组,并将子数组放入数组列表中。如果数组的大小不是所选最大大小的倍数,则最后一个数组会更小。

        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;
        }
        

        【讨论】:

          【解决方案6】:

          这是一个拆分数组的函数,你可以使用下面的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));
          }
          }
          

          【讨论】:

            【解决方案7】:

            这是一种方便的方法,可将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 条件使用&lt;=,这比&lt; ... + 1 更有意义。
            2. 将停止索引放在临时字段中可减少最后一个 if 块中的计算次数。

            (单元测试)

            【讨论】:

              【解决方案8】:
              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();
                  }
              }
              

              【讨论】:

                【解决方案9】:

                我知道这个问题已经很老了,但是,嘿,有人可以为这个常见问题搜索另一个干净的 Java 答案。 如果您正在使用 List (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
                

                为了摆脱“计数器”,有些人可能会改变 NewArray 为 List 方法构建的方式,例如:

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

                希望这对未来的人有所帮助!

                【讨论】:

                  猜你喜欢
                  • 2015-11-14
                  • 2012-05-15
                  • 2020-10-01
                  • 1970-01-01
                  • 2012-07-04
                  • 1970-01-01
                  • 2016-12-07
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多