2

I am tasked with fixing a problem where this code returns string values but because the iterations add null elements it needs to trim or remove those. During debug the value of the array contains mostly "All elements are null", but other solutions like data.removeAll(Collections.singleton(null)); do not work because it is the elements that are null and it still returns as the original size. Is there a way to remove these elements after the iterations of the initial loop or should this be done inside the loop where data is assigned the "value"?

Code:

    private String[][] getStringsFromSpreadSheet(Sheet ws) {
    int rowNum = ws.getLastRowNum() + 1;
    int colNum = ws.getRow(0).getLastCellNum();
    String[][] data = new String[(rowNum - 1)][colNum];

    int k = 0;
    for (int i = 1; i < rowNum; i++) {
        ws.getRow(i);
        if (ws.getRow(i) != null) {
            for (int j = 0; j < colNum; j++) {
                if (ws.getRow(i).getCell(j) != null) {
                    String value = ws.getRow(i).getCell(j).toString();
                    if (!value.toString().isEmpty()) {
                        data[k][j] = value;
                    }
                }
            }
        }
        k++;
    }
    return data;
}
7
  • 4
    The size of an array represents how much space it has allocated, and has nothing to do with whether any values in it are null or not. If you want a dynamically sized data structure, use a List instead. Commented Sep 17, 2015 at 17:10
  • 1
    You can't remove elements from an array; you can only assign different values. If you don't want null elements in your array, you'd have to assign non-null values to the elements. Commented Sep 17, 2015 at 17:12
  • @azurefrog correct, however converting to List then attempting to remove the nulls has failed as the size remains the same where I am constrained by other requirements to only return the string [][] but with a "trimmed" size. Commented Sep 17, 2015 at 17:23
  • 2
    Collection.addAll(dataList, data) isn't doing what you think it is. What you're doing here is creating a list of arrays of string. When you try to remove null from the list, nothing comes out, because it's full of array references, none of which are null, even though the arrays themselves have null values. Commented Sep 17, 2015 at 18:08
  • 1
    It's too long to explain in a comment, so I've added an answer with some sample code which shows how to convert a 2d array to a nested List and back, including trimming nulls from it while it's in its List form. Let me know if that helps. Commented Sep 17, 2015 at 19:14

3 Answers 3

1

You can easily trim out null values from a List, but you've been trying to convert your array to a List incorrectly.

Since you've got a two-dimensional array, you need to create a nested list (List<List<String>>) to store the data.

For instance, let's start with a mostly empty String[][]:

    String[][] data = new String[3][3];
    data[0][0] = "foo";
    data[1][1] = "bar";

    //data is a 3x3 array
    for (int i=0; i<data.length; i++) {
        System.out.println(Arrays.toString(data[i]));
    }
    //[foo, null, null]
    //[null, bar, null]
    //[null, null, null]

We can take each sub-array, convert it to a list, trim it, and then add the non-empty lists to an enclosing list, like so:

    List<List<String>> dataList = new ArrayList<>();
    for (int i=0; i<data.length; i++) {
        List<String> temp = new ArrayList<>();
        Collections.addAll(temp, data[i]);
        temp.removeAll(Collections.singleton(null));
        if (!temp.isEmpty()) {
            dataList.add(temp);
        }
    }

We can then convert the list back to a String[][], which will be "trimmed" of null data, like so:

    String[][] newData = new String[dataList.size()][];
    for (int i=0; i<dataList.size(); i++) {
        List<String> subList = dataList.get(i);
        newData[i] = subList.toArray(new String[subList.size()]);
    }

    //newData is a 2x1 array
    for (int i=0; i<newData.length; i++) {
        System.out.println(Arrays.toString(newData[i]));
    }
    //[foo]
    //[bar]
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for helping me understand this.
0

All you need to do is set it to blank string. check the else clause.

private String[][] getStringsFromSpreadSheet(Sheet ws) {
int rowNum = ws.getLastRowNum() + 1;
int colNum = ws.getRow(0).getLastCellNum();
String[][] data = new String[(rowNum - 1)][colNum];

int k = 0;
for (int i = 1; i < rowNum; i++) {
    ws.getRow(i);
    if (ws.getRow(i) != null) {
        for (int j = 0; j < colNum; j++) {
            if (ws.getRow(i).getCell(j) != null) {
                String value = ws.getRow(i).getCell(j).toString();
                if (!value.toString().isEmpty()) {
                    data[k][j] = value;
                }
            } else {
                data[k][j] = "";
            }
        }
    }
    k++;
}
return data;

Now the data would not have any null values but it may have blank / empty strings.

Comments

0

Based on your comments it seems that you have to return a String[][] for getStringsFromSpreadSheet. Is this correct? If so there is not a nice way to keep track of how many cells are null/not null. 2D arrays have to be rectangular. So if one of your rows has 3 columns populated and one row only has 1 column populated, the array has to be at least 3 columns wide. I have tried to represent this visually below.

Row | Column 1  | Column 2  | Column 3  |
 1  | something | something | something |
 2  | something |    null   |    null   |

So for the above data you have to declare a 2D array at least 2x3 to fit all of your data. No matter what, if one of your rows does not populate all 3 columns, you will always have a null cell for that row. Array.length will always return the size of the array, never the count of how many are null/not null.

Your options are limited if you can only return a String[][]. If you are able to return something else, we can work through some options.

2 Comments

...what? 2D arrays don't have to be rectangular. String[][] array = new String[2][]; array[0] = new String[3]; array[1] = new String[1]; totally works and creates a non-rectangular array.
Did not realize you could do that. Thanks @LouisWasserman for the input. If the "something" was in column 2 though, we would still need to create a 1x2 Array and 1 cell would still need to be null. Still not a clean way to figure out how many are null/not null using String[][]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.