【问题标题】:How to remove a row from a 2d array?如何从二维数组中删除一行?
【发布时间】:2010-12-20 18:44:18
【问题描述】:

我有一个简单的数组,有点像这样:

1 2 3 4 5 6 7 8 9
6 2 7 2 9 6 8 10 5
2 6 4 7 8 4 3 2 5
9 8 7 5 9 7 4 1 10
5 3 6 8 2 7 3 7 2

所以,我们称之为matrix[5][9]。我现在希望删除此矩阵中包含某个值的每一行,在本例中为 10,所以我只剩下...

1 2 3 4 5 6 7 8 9
2 6 4 7 8 4 3 2 5
5 3 6 8 2 7 3 7 2

【问题讨论】:

    标签: java arrays multidimensional-array


    【解决方案1】:

    这是一个您可以运行的示例类,我相信它可以满足您的需求。从二维数组中删除行是一件棘手的事情,因为就像@KalebBrasee 所说,你不能真正“删除”它们,而是你必须制作一个全新的二维数组。希望这会有所帮助!

    import java.util.ArrayList;
    import java.util.List;
    
    public class Matrix {
        private double[][] data;
    
        public Matrix(double[][] data) {
            int r = data.length;
            int c = data[0].length;
            this.data = new double[r][c];
            for (int i = 0; i < r; i++) {
                for (int j = 0; j < c; j++) {
                    this.data[i][j] = data[i][j];
                }
            }
        }
    
        /* convenience method for getting a
           string representation of matrix */
        public String toString() {
            StringBuilder sb = new StringBuilder(1024);
            for (double[] row : this.data) {
                for (double val : row) {
                    sb.append(val);
                    sb.append(" ");
                }
                sb.append("\n");
            }
    
            return (sb.toString());
        }
    
        public void removeRowsWithValue(final double value) {
            /* Use an array list to track of the rows we're going to want to
               keep...arraylist makes it easy to grow dynamically so we don't
               need to know up front how many rows we're keeping */
            List<double[]> rowsToKeep = new ArrayList<double[]>(this.data.length);
            for (double[] row : this.data) {
                /* If you download Apache Commons, it has built-in array search
                  methods so you don't have to write your own */
                boolean found = false;
                for (double testValue : row) {
                    /* Using == to compares doubles is generally a bad idea
                       since they can be represented slightly off their actual
                       value in memory */
                    if (Double.compare(value, testValue) == 0) {
                        found = true;
                        break;
                    }
                }
    
                /* if we didn't find our value in the current row,
                  that must mean its a row we keep */
                if (!found) {
                    rowsToKeep.add(row);
                }
            }
    
            /* now that we know what rows we want to keep, make our
               new 2D array with only those rows */
            this.data = new double[rowsToKeep.size()][];
            for (int i = 0; i < rowsToKeep.size(); i++) {
                this.data[i] = rowsToKeep.get(i);
            }
        }
    
        public static void main(String[] args) {
            double[][] test = {
                    {1, 2, 3, 4, 5, 6, 7, 8, 9},
                    {6, 2, 7, 2, 9, 6, 8, 10, 5},
                    {2, 6, 4, 7, 8, 4, 3, 2, 5},
                    {9, 8, 7, 5, 9, 7, 4, 1, 10},
                    {5, 3, 6, 8, 2, 7, 3, 7, 2}};
    
            //make the original array and print it out
            Matrix m = new Matrix(test);
            System.out.println(m);
    
            //remove rows with the value "10" and then reprint the array
            m.removeRowsWithValue(10);
            System.out.println(m);
        }
    }
    

    【讨论】:

    • 我现在正在尝试代码,当它达到 10 时,我得到了一个 ArrayIndexOutOfBoundsException。
    • 我想我已经找到了问题所在。您是否有机会查看我的编辑以查看是否可以解决?
    • 粘贴在这里肯定可以正常运行,所以我会看看你的编辑。
    • 问题是我的 show 方法不起作用,但我已经用你的 toString 方法替换了它。它有效,尽管它在删除行的位置留下了空隙。不管怎样,谢谢你的帮助!
    【解决方案2】:

    使用System.arraycopy 使用java.util.List 而不是数组。 ArrayList 具有对随机元素的快速访问和缓慢的 remove 方法,与 LinkedList 正好相反。你必须自己选择。

    【讨论】:

    • 我认为您只需将 %20 用于空格
    【解决方案3】:

    此时,您必须重新创建数组并丢弃旧数组。无法更改现有数组的维度 - 如果想要这种类型的数据结构,那么您应该基于 Collections (ArrayList&lt;ArrayList&lt;Double&gt;&gt;) 构建矩阵,在那里您可以轻松删除一行。

    回到数组——这个想法是收集你想要保留的所有行(double[] 数组),用这些行创建一个结果数组,然后用 Matrix 上的新行替换旧的:

    public void doSomethingWith(Matrix in) {
      List<double[]> survivingRows = new ArrayList<double[]>();
      for (double[] row:in.getRows()) {
        if (isAGoodOne(row)) {
          survivingRows.add(row);
        }
      }
    
      double[][] result = new double[survivingRows][];
      for (int i = 0; i < result.length; i++) {
        result[i] = survivingRows.get(i);
      }
      in.setArray(result);
    }
    

    【讨论】:

      【解决方案4】:

      您不能从 Java 内置数组数据结构中删除元素。您必须创建一个长度比第一个数组小一的新数组,并将所有数组复制到该数组中,除了您要删除的数组。

      【讨论】:

      • 当我使用 Matrix 类来传递一个矩阵时,只需输入一个并输出一个较短的矩阵是没有问题的。一旦我在单元格中找到值,我只是坚持如何从我的新矩阵中“删除”该行。
      【解决方案5】:

      我的 java 语法有点生疏,但以下,如果被视为伪代码将工作

      public Matrix removeRows(Matrix input) {
          int[][] output = new int[input.numRows][input.numColumns]();
          int i = 0;
          for (int[] row : input.rows()) {      // Matrix.rows() is a method that returns an array of all the rows in the matrix
              if (!row.contains(10)) {
                  output[i] = row;
              }
          }
          return output
      

      【讨论】:

        【解决方案6】:

        我的看法:

        import java.util.Arrays;
        
        public class RemoveArrayRow {
            private static <T> T[] concat(T[] a, T[] b) {
                final int alen = a.length;
                final int blen = b.length;
        
                if (alen == 0) {
                    return b;
                }
        
                if (blen == 0) {
                    return a;
                }
        
                final T[] result = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), alen + blen);
        
                System.arraycopy(a, 0, result, 0, alen);
                System.arraycopy(b, 0, result, alen, blen);
        
                return result;
            }
        
            public static void main(String[] args) {
                double[][] d  = { {11, 2, 3, 4, 5, 6, 7, 8, 9, 0},
                                  {12, 2, 3, 4, 5, 6, 7, 8, 9, 1},
                                  {13, 2, 3, 4, 5, 6, 7, 8, 9, 2},
                                  {14, 2, 3, 4, 5, 6, 7, 8, 9, 3},
                                  {15, 2, 3, 4, 5, 6, 7, 8, 9, 4} };
        
                //remove the fourth row:
        
                // (1)
                double[][] d1 = concat(Arrays.copyOf(d, 3), Arrays.copyOfRange(d, 4, 5));
        
                // (2)
                double[][] d2 = new double[d.length - 1][d[0].length];
                System.arraycopy(d, 0, d2, 0, 3);
                System.arraycopy(d, 4, d2, 3, 1);
        
                System.out.print(d1.length);
                System.out.print(d2.length);
            }
        }
        

        (1)
        如果排除用于连接两个数组的concat() 函数,则在一行中完成:
        double[][] d1 = concat(Arrays.copyOf(d, 3), Arrays.copyOfRange(d, 4, 5));
        参见this question。这就是concat() 函数的代码来源。

        (2)
        这种方法速度更快,并且只使用已经可用的函数。

        【讨论】:

          【解决方案7】:

          由于无法避免创建新的二维数组来包含删除后的数据,因此首先创建一个与 a[][] 维度相同的新二维 int[][] b。其次,循环 a[][],将 a 赋值给 b,当 a 包含特定值时将 b 行上移。和健全性检查最后一行,其中可以包含特定数据。

          public static int[][] remove(int[][] a, int v) {
              int r = a.length;
              int c = a[0].length;
          
              int[][] b = new int[r][c];
          
              int red = 0;
              boolean s = false;
              for (int i = 0; i < r; i++) {
                  for (int j = 0; j < c; j++) {
                      b[i - red][j] = a[i][j];
                      if (a[i][j] == v) {
                          red += 1;
                          if(i==r-1){
                              s = true;
                          }
                          break;
                      }
                  }
              }
              //check last row
              if(s){
              for(int i = r-red;i <r-red +1; i++ )
                  for (int j = 0; j<c; j++){
                      b[i][j] = 0;
                  }
              }
              return b;
          }
          
          public static void main(String[] args){
              int[][] a = { {1, 2, 3, 4, 5, 6, 7, 8, 1},
                      {6, 2, 7, 2, 9, 6, 8, 10, 5},
                      {2, 6, 4, 7, 8, 4, 2, 2, 5},
                      {9, 8, 7, 5, 9, 7, 4, 1, 1},
                      {5, 3, 6, 8, 2, 7, 3, 1, 1} };
          
              print(remove(a, 10));
          
          
          }
          
          public static void print(int[][] a) {
              int r = a.length;
              int c = a[0].length;
          
          
              int red = 0;
              for (int i = 0; i < r; i++) {
                  System.out.printf("\nrow %d, \n", i);
                  for (int j = 0; j < c; j++) {
                      System.out.printf("%d, ", a[i][j]);
                  }
              }
          }
          

          【讨论】:

            【解决方案8】:

            这可能不是一个精确的解决方案,而是一个关于如何使用 System.arraycopy 实现它的概念。

            在下面的示例中,我想复制除第一行之外的所有行。在您的情况下,您可以跳过那些包含 10 的行。

            String[][] src = getSheetData(service, spreadSheetId, range);
            String[][] dest = new String[src.length-1][src[0].length];
            
            for (int i = 1; i < src.length; i++) {
            System.arraycopy(src[i], 0, dest[i-1], 0, src[0].length-1);
            }
            

            参考:https://docs.oracle.com/javase/6/docs/api/java/lang/System.html#arraycopy%28java.lang.Object,%20int,%20java.lang.Object,%20int,%20int%29

            【讨论】:

              【解决方案9】:

              您可以为此使用IntStream.noneMatch 方法:

              int[][] arr1 = {
                      {1, 2, 3, 4, 5, 6, 7, 8, 9},
                      {6, 2, 7, 2, 9, 6, 8, 10, 5},
                      {2, 6, 4, 7, 8, 4, 3, 2, 5},
                      {9, 8, 7, 5, 9, 7, 4, 1, 10},
                      {5, 3, 6, 8, 2, 7, 3, 7, 2}};
              
              int[][] arr2 = Arrays.stream(arr1)
                      .filter(row -> Arrays.stream(row).noneMatch(i -> i == 10))
                      .toArray(int[][]::new);
              
              // output
              Arrays.stream(arr2).map(Arrays::toString).forEach(System.out::println);
              

              输出:

              [1, 2, 3, 4, 5, 6, 7, 8, 9]
              [2, 6, 4, 7, 8, 4, 3, 2, 5]
              [5, 3, 6, 8, 2, 7, 3, 7, 2]
              

              【讨论】:

                猜你喜欢
                • 2016-11-27
                • 2023-03-31
                • 1970-01-01
                • 2018-04-05
                • 1970-01-01
                • 2021-02-23
                • 1970-01-01
                • 1970-01-01
                • 2021-06-26
                相关资源
                最近更新 更多