SaturnsBelt
SaturnsBelt

Reputation: 281

How can I remove "null" elements in an array?

I am currently doing a coding challenge that states:

Given a List of words, return the words that can be typed using letters of alphabet on only one row's of American keyboard like the image below (which is an image of a QWERTY keyboard).

Example:

Input: ["Hello", "Alaska", "Dad", "Peace"]
Output: ["Alaska", "Dad"]

What I have done to solve this is to write a for loop, then do if statements that replace all rows (like QWERTY) to "" and if the length of this is greater than 1, then you can not type that word in one row. I am getting almost the correct output, but my array contains null elements.

My output is:

[null,"Alaska","Dad",null]

How can I return an array that does not have these null elements? To complete this challenge, I have to return a String[] array. I can not use an ArrayList to return.

class Solution {
    public String[] findWords(String[] words) {
    String[] result = new String[words.length];

    String row1 = "qwertyuiop";
    String row2 = "asdfghjkl";
    String row3 = "zxcvbnm";

    for (int i = 0 ; i < words.length; i++) {
        if (words[i].toLowerCase().replaceAll("[" + row1 + "]", "").length() == 0 ||
           words[i].toLowerCase().replaceAll("[" + row2 + "]", "").length() == 0 ||
           words[i].toLowerCase().replaceAll("[" + row3 + "]", "").length() == 0) {
            if (words[i] != null) {
                result[i] = words[i];
            }


        }
       }

    return result;
    }


}

Upvotes: 5

Views: 6615

Answers (7)

KarlMathuthu
KarlMathuthu

Reputation: 84

One way to reduce the size of an array with null elements is to use the .filter() method. This method will go through each element of the array and check if it is not null. If it is not null, the element will be added to a new array. The new array will then be returned and will only contain the elements that were not null.

Upvotes: 0

GregH
GregH

Reputation: 5459

You can use the following to remove all nulls from an array of strings:

List<String> list = new ArrayList<String>(Arrays.asList(myArray));
list.removeAll(Collections.singleton(null));
String[] result = list.toArray(new String[list.size()]);

Upvotes: 4

GBlodgett
GBlodgett

Reputation: 12819

The original problem is that you were returning an Array that was the same size as the original Array. So if any of the elements didn't match, one slot in the Array will be left it's default value, which is null. You need to keep track of how many items need to be copied over. You can do this with a counter and Arrays.copyOf().

Just for what it's worth, Java 8+ we can do:

public static String[] findWords(String[] words) {
    return Stream.of("asdfghjkl", "qwertyuiop", "zxcvbnm")
                 .filter(row -> Arrays.stream(words)
                           .anyMatch(e -> e.replaceAll("[" + row + "]","")                  
                           .isEmpty())
                 ).toArray(String[]::new);
}

Which will create a Stream of the rows using Stream.of and filter through the words Array and only keep the ones that are only made up of letters in a single row on the keyboard

Upvotes: 2

Amanuel B.
Amanuel B.

Reputation: 1

Try storing the non-null values in a different variable and count them, initialize another array with the count and copy the values to the latter array. Demonstrated as follows:

class Solution {
    public static String[] findWords(String[] words) {
    String[] resultWithNull = new String[words.length];
    int counter = 0;

    String row1 = "qwertyuiop";
    String row2 = "asdfghjkl";
    String row3 = "zxcvbnm";

    for (int i = 0 ; i < words.length; i++) {
      if (words[i].toLowerCase().replaceAll("[" + row1 + "]", "").length() == 0 ||
        words[i].toLowerCase().replaceAll("[" + row2 + "]", "").length() == 0 ||
        words[i].toLowerCase().replaceAll("[" + row3 + "]", "").length() == 0) {
        if (words[i] != null) {
         resultWithNull[counter] = words[i];
         ++counter;
       }
     }
   }

   String[] result = new String[counter];
   for (int i = 0 ; i < counter; i++) {
      result[i] = resultWithNull[i];
   }
   return result;
 }

}

Upvotes: 0

P. van der Laan
P. van der Laan

Reputation: 251

Using this one liner:

Arrays.stream(result).filter(Objects::nonNull).toArray(String[]::new)

Filters the array and get all objects that are nonNull. Do not forget to transform the stream back to an array.

Upvotes: 6

Patric
Patric

Reputation: 1627

You could just use an ArrayList instead of an array and then call toArray at the end if you really need to return a String array.

    public String[] findWords(String[] words) {
        List<String> result = new ArrayList<>();

        String row1 = "qwertyuiop";
        String row2 = "asdfghjkl";
        String row3 = "zxcvbnm";

        for (int i = 0; i < words.length; i++) {
            if (words[i].toLowerCase().replaceAll("[" + row1 + "]", "").length() == 0 ||
                    words[i].toLowerCase().replaceAll("[" + row2 + "]", "").length() == 0 ||
                    words[i].toLowerCase().replaceAll("[" + row3 + "]", "").length() == 0) {
                if (words[i] != null) {
                    result.add(words[i]);
                }
            }
        }

        return result.toArray(new String[0]);
    }

Upvotes: 1

hayrettinm
hayrettinm

Reputation: 72

Your result array is initialized with the size of words array. You can use ArrayList for dynamically assignment.

After you can return ArrayList's toArray method, so that you will return desired striing array.

If you aren't allowed to use ArrayList in the code, I would look for how to size my result array dynamically.

Upvotes: 0

Related Questions