2

I've been trying out the new section on codingbat, map1 & 2. I've finished map1, and I'm halfway through map2 but I'm just stuck on this one problem. I can't seem to figure out how to combine two strings.

Given an array of non-empty strings, return a Map<String, String> with a key for every different first character seen, with the value of all the strings starting with that character appended together in the order they appear in the array.

Examples:

firstChar(["salt", "tea", "soda", "toast"]) → {"t": "teatoast", "s": "saltsoda"}
firstChar(["aa", "bb", "cc", "aAA", "cCC", "d"]) → {"d": "d", "b": "bb", "c": "cccCC", "a": "aaaAA"}
firstChar([]) → {}

Here's my code:

public Map<String, String> firstChar(String[] strings)                       
{             
  Map<String, String> map = new HashMap<String, String>();       
  String x = "";         
   for ( String s: strings )    
     {
      if ( s.substring(0,1) == s.substring(0,1))   
       x += s;   
         map.put(s.substring(0,1), x);        
     }     
  return map;   
}

I only get {"d": "d", "b": "", "c": "", "a": ""}

I've also tried s.substring(0, 1, map.get(s) + map.get(s)) which only returns null. If anyone could explain this to me it would be greatly appreciated!

Thank you !

Dici
  • 25,226
  • 7
  • 41
  • 82
Cat
  • 21
  • 3
  • 1
    What does your condition do? You compare the result of substring with itself. – Michael Hoff Jul 31 '16 at 04:52
  • Possible duplicate of [How do I compare strings in Java?](http://stackoverflow.com/questions/513832/how-do-i-compare-strings-in-java) – azurefrog Jul 31 '16 at 04:56
  • I can not test this right now, but you want to do the following: For each string compute `k = s.charAt(0)`. If `k` is already in the map, get its value, concatenate it with `s` and put it again for `k`. If not simply put `s` for `k`. – Michael Hoff Jul 31 '16 at 04:57

4 Answers4

4

Your logic is wrong, you are comparing the first character of the string with itself. Also, although it is not diretly your problem here, you are comparing strings with == instead of equals. == is used to compare references, equals is used to compare logical equality. Plus, for getting the first character of a string you can just use s.charAt(0). Ironically, you would not have had this issue if you had done it because String.charAt returns a char, which is a primitive type and thus can be compared safely using ==.

Code with various improvements and fixes:

public Map<String, String> firstChar(String[] strings) {             
  Map<String, String> map = new HashMap<>();                
  for (String s: strings) {
     map.merge(String.valueOf(s.charAt(0), s, String::concat);   
  }     
  return map;   
}

Or pre-Java 8:

public Map<String, String> firstChar(String[] strings) {             
  Map<String, String> map = new HashMap<>();                
  for (String s: strings) {
     String key   = String.valueOf(s.charAt(0));
     String value = map.get(key);
     map.put(key, (value == null ? "" : value) + s);        
  }     
  return map;   
}
Dici
  • 25,226
  • 7
  • 41
  • 82
  • Why do you consider `key = String.valueOf(s.charAt(0))` to be better than `key = s.substring(0, 1)`, which seems much more concise and to the point? – Andreas Jul 31 '16 at 05:16
  • Thank you. `The method getOrDefault(char, String) is undefined for the type Map` is an error I'm getting though. I tried tweaking with it, and I'm not getting very far. Sorry for having to be spoonfed like this! I did have to do s.substring(0,1), I'm getting both the strings combined but it still has null in front of it. – Cat Jul 31 '16 at 05:18
  • Using `substring` for getting the first character is far-fetched and will probably result in a `StringBuilder` being allocated with a size greater than 1 all for nothing. – Dici Jul 31 '16 at 05:18
  • @Cat `getOrDefault()` was added in Java 8. – Andreas Jul 31 '16 at 05:19
  • @Cat It probably means you are not using Java 8. I will give you a pre-Java 8 answer, but I recommend you to move to Java 8 anyway – Dici Jul 31 '16 at 05:19
  • 1
    Thank you, I appreciate it! I'm not sure what version of Java codingbat is right now. – Cat Jul 31 '16 at 05:21
  • @Dici Using `substring()` for getting a `String` is not farfetched, and it definitely does not use `StringBuilder`. – Andreas Jul 31 '16 at 05:21
  • Mm yeah it can just allocate an array directly since the size is known. But it's still far-fetched, using `charAt` makes it clearer what is the intent. By the way, I must convert it as a `String` only to conform to the API of the OP but the real **correct** API should return `Map`. What's the point of allowing strings while we are expecting only single-characters ? That's just room for unexpected bugs – Dici Jul 31 '16 at 05:25
  • Thanks for the site! – Cat Jul 31 '16 at 05:27
  • @Dici Since you were using the Java 8 `getOrDefault`, why not use `merge`? As in: `for (String s : strings) { map.merge(s.substring(0, 1), s, String::concat); }` – Andreas Jul 31 '16 at 05:30
  • @Andreas why not, it's doing slightly more than what I want but it's concise – Dici Jul 31 '16 at 05:38
0
public Map<String, String> firstChar(String[] strings) {
Map<String, String> map = new HashMap<String, String> ();
  for (String s:strings) {
  if (!map.containsKey(s.substring(0,1))) {  // first time we've seen this string
      map.put(s.substring(0,1), s);

  }
  else
  {
     String existing = map.get(s.substring(0,1));
      map.put(s.substring(0,1), existing+s);
  }

}
  return map;
}
0
public Map<String, String> firstChar(String[] strings) {
    Map<String, String> map = new HashMap<String, String>(strings.length);
    for (String string : strings) {
        String firstCharacter = String.valueOf(string.charAt(0));
        map.put(firstCharacter, map.getOrDefault(firstCharacter, "") + string);
    }
    return map;
}
Bresiu
  • 2,123
  • 2
  • 19
  • 31
0
public Map<String, String> firstChar(String[] strings) {
    Map<String, String> str = new HashMap<String, String>();
    for (int i = 0; i < strings.length; i++) {
        String value = "";
        for (int j = 0; j < strings.length; j++) {
            if (strings[i].charAt(0) == strings[j].charAt(0)) {
                value = value+strings[j];
            }
        }
        str.put(Character.toString(strings[i].charAt(0)), value);
    }
    return str;
}
Ravi Vyas
  • 410
  • 6
  • 12