5

I have a simple array, sort of like this:

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

So, let's call this matrix[5][9]. I wish to now remove every row within this matrix that contains a certain value, in this case 10, so I am left with...

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
Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63
AlexT
  • 561
  • 1
  • 8
  • 22

9 Answers9

9

Here's a sample class you can run that I believe does what you're looking for. Removing rows from 2D arrays is tricky business because like @KalebBrasee said, you can't really "remove" them, but rather you have to make a whole new 2D array instead. Hope this helps!

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);
    }
}
Community
  • 1
  • 1
Brent Writes Code
  • 19,075
  • 7
  • 52
  • 56
  • I'm trying out the code now and I'm getting an ArrayIndexOutOfBoundsException when it hits a 10. – AlexT Nov 26 '09 at 19:25
  • I think I've figured out the problem. Is there any chance you could look at my edit to see if it can be resolved? – AlexT Nov 26 '09 at 20:02
  • It definitely runs ok as pasted in here, so I'll take a look at your edits. – Brent Writes Code Nov 26 '09 at 21:18
  • The problem was my show method not working, but I've replaced it with your toString method. It works, although it leaves a gap where the row was removed. Either way, thanks for your help! – AlexT Nov 28 '09 at 18:49
5

Use System.arraycopy or use java.util.List instead of arrays. ArrayList has fast access to random elements and a slow remove method, it's the opposite with LinkedList. You have to choose for yourself.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Krzysiek Goj
  • 1,598
  • 4
  • 16
  • 18
2

At the and you have to recreate the array and discard the old one. Changing the dimension of an existing array is not possible - if want this type of datastructure, then you should build the matrix based on Collections (ArrayList<ArrayList<Double>>), there you can remove a row easily.

Back to arrays - the idea is to collect all rows (double[] arrays) that you want to keep, create a result array with those rows and replace the old one with the new on on 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);
}
Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
1

You can't remove elements from the Java built-in array data structure. You'll have to create a new array that has a length one less than the first array, and copy all the arrays into that array EXCEPT the one you want to remove.

Kaleb Brasee
  • 51,193
  • 8
  • 108
  • 113
  • As I'm using the Matrix class to pass a Matrix in there's no problem with simply taking one in and outputting a shorter Matrix. I'm just stuck on how I would go about "removing" that row from my new Matrix once I had found the value within a cell. – AlexT Nov 26 '09 at 18:54
0

My take:

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)
If you exclude the concat() function used for concatenating two arrays, it's done in one line:
double[][] d1 = concat(Arrays.copyOf(d, 3), Arrays.copyOfRange(d, 4, 5));
See this question as well. That's where the code for the concat() function comes from.

(2)
This method is faster and only uses already available functions.

Community
  • 1
  • 1
Marius Burz
  • 4,555
  • 2
  • 18
  • 28
0

My java syntax is a little rusty, but the following, if treated as pseudocode will work

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
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
0

Since it cannot avoid creating new 2D array to contain the after-removed data, firstly, create a new 2D int[][] b with same dimension as a[][]. secondly, loop through a[][], assign a to b and move b row up when a contain specific value. and sanity check the last row, which can contain specific data.

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]);
        }
    }
}
Sola Yang
  • 975
  • 8
  • 8
0

This may not be an exact solution but a concept of how you can achieve it using System.arraycopy.

In the example below, I want to copy all the rows except the first row. In your case, you can skip those rows which contain 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);
}

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

hemanto
  • 1,900
  • 17
  • 16
0

You can use IntStream.noneMatch method for this purpose:

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

Output:

[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]