5

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


}
elbraulio
  • 994
  • 6
  • 15
SaturnsBelt
  • 271
  • 2
  • 13
  • see https://stackoverflow.com/questions/24112715/java-8-filter-array-using-lambda in the question replace `i > 0`with `i != null` – leonardkraemer Jan 08 '19 at 21:09
  • 3
    Possible duplicate of [Remove Null Value from String array in java](https://stackoverflow.com/questions/4150233/remove-null-value-from-string-array-in-java) – leonardkraemer Jan 08 '19 at 21:11

7 Answers7

6

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.

P. van der Laan
  • 231
  • 1
  • 9
4

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()]);
Slaw
  • 37,820
  • 8
  • 53
  • 80
GregH
  • 5,125
  • 8
  • 55
  • 109
2

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

GBlodgett
  • 12,704
  • 4
  • 31
  • 45
1

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]);
    }
Patric
  • 1,489
  • 13
  • 28
0

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.

hayrettinm
  • 72
  • 5
0

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

}

0

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.