Technical Interview Question Answers: Array of Letters to Hash of Letter Counts, in Three Languages

I wrote some Java you guys!

In addition to all of my blog posts about personal finance, I thought it might be interesting and valuable to start a more technical series of posts geared toward those of my readers who are software developers. I’m going to kick this concept off by answering a question I got in an actual technical interview: given an array of letters in the alphabet, which can appear multiple times, return a hash of letter counts sorted alphabetically. For example, the following array:

["s", "a", "b", "b", "h", "d", "e", "f", "o", "q", "r", "w", "s", "c", "u", "g", "a", "h", "h", "r"]

should return the following hash of key-value pairs:

{"a"=>2, "b"=>2, "c"=>1, "d"=>1, "e"=>1, "f"=>1, "g"=>1, "h"=>3, "o"=>1, "q"=>1, "r"=>2, "s"=>2, "u"=>1, "w"=>1}

There are several reasons I decided to start here: first, I failed the interview, possibly because it was my first time coding on a whiteboard and coding on a whiteboard is, well, terrible—ask any developer, they’ll tell you. Second, this interview question could theoretically pop up for my more-technical readers, so this could be a good resource for them. Third, I wound up using a solution to this problem in a real web application several times at my job at Radial Development Group (AFTER the interview, of course), which means it is, at the very least, a practical question.

The question was given at a fintech/payment processing company, which, as you may guess, means that they work in the Java programming language. Possibly because they were aware I’m unfamiliar with Java, they told me I could write the answer in any language I want (I chose my first and favorite language, Ruby). They also told me that their stack uses JavaScript (which has nothing to do with Java, non-coders) pretty frequently.

So I decided to answer the question in all three languages for this blog post. Let’s start with Ruby.

My Answer in Ruby

First and foremost, I defined a sample array that we’re going to be manipulating:

letter_array = ["s", "a", "b", "b", "h", "d", "e", "f", "o", "q", "r", "w", "s", "c", "u", "g", "a", "h", "h", "r"]

Pretty simple, right? `lettersarray[0]` will return ‘s’, `lettersarray[1]` returns ‘a’, and so on. Ruby lets you use single or double quotes interchangeably (‘’ vs “”), so this array could just as easily have single quotes around each character. The only significant difference is that double quotes allow string interpolation. It’s an urban legend that single quotes are more performant in Ruby.

I have some duplicates to make sure that my compiler actually counts, so the key ‘h’ returns 3, not 1.

Now we need to define a Ruby method that accepts the array, generates a hash, sorts it, then returns the sorted hash (line numbers added for reference):

1  def count_and_sort_letters array
2 letter_counts = {}
3 array.each_with_object(letter_counts) do |letter, letter_counts|
4 if letter_counts[letter]
5 letter_counts[letter] += 1
6 else
7 letter_counts[letter] = 1
8 end
9 end
10 letter_counts.sort_by{|k, v| k}.to_h
11 end

Then call the method with the letter_array:

count_and_sort_letters letter_array

Great! So what am I doing here? Let’s break it down:

  • Line 1 defines a Ruby method, which I named count_and_sort_letters. It accepts an argument, array, which we'll be manipulating throughout the rest of the method. The method is closed on line 11 with end.
  • Line 2 defines an empty hash, letter_counts. I could inline this into line 3 by passing each_with_object an empty hash rather than letter_counts, but I only wanted to sort_by once, since sort operations are generally expensive. Therefore, I needed the variable declared outside of the each block.
  • Line 3 begins the Ruby each_with_object block. It accepts an enumerable as an argument (an array or a hash, generally, and in this case my empty object, letter_counts). It then passes two arguments into the block: the current element in the enumerable (whichever letter we're on in letter_counts), and the object we passed in.
  • We don’t want to return values of 0 in the hash; that is, "p" => 0 should not be returned. So on line 4 I check whether letter_counts[letter] is truthy or not (in other words, it checks whether that key has already been given a value, because nil is falsey). This means the first iteration is checking whether letter_counts["s"] exists or not, and returns false. On the fourth iteration, however, letter_counts["b"] DOES exist, so it executes line 5, incrementing letter_counts["b"] by 1.
  • In the instance that the key isn’t already assigned in the letter_counts hash, the else statement beginning on line 6 is executed, creating that key with a value of 1 in the hash. So in the first iteration, letter_counts["p"] gets the value 1.
  • After the each_with_object loop finished, I call sort_by on the hash on line 10. I pass it a one-line block (in Ruby, { } is the one-liner equivalent to do ... end). It accepts the key and value of each element in the hash, k and v, and is told to sort using k rather than v (the letter, not the count). Since Ruby's sort_by returns an array, I then call to_h to convert it back to a hash instead. Ruby methods return their last line unless you tell them to do otherwise, so I don't need a return statement here.

The result is what we wanted:

{"a"=>2, "b"=>2, "c"=>1, "d"=>1, "e"=>1, "f"=>1, "g"=>1, "h"=>3, "o"=>1, "q"=>1, "r"=>2, "s"=>2, "u"=>1, "w"=>1}

Some notes:

  • Ruby acts like Ruby a lot in this example: it returns more or less what you want and doesn’t throw a lot of errors without much effort on my part, but it then needs to be told to sort properly and return a hash.
  • Like many Ruby developers, I sometimes forget where Ruby ends and Rails begins; I tried calling .present? on letter_counts[letter] and kept getting an error, before finally remembering that is from ActiveSupport in Rails, not Ruby. My if statement works fine without it in this instance, but it wouldn't act quite so gracefully if you pass in nil in an effort to trip it up.

My Answer in JavaScript

In my experience writing JavaScript in an actual app, developers tend to use libraries like Lodash to get many of the helpful functions other languages take for granted (simple sorting and type checking functionality, for example). For my JavaScript example, I didn’t do this, but I did use ES6 syntax to make for slightly simpler reading.

Again, I defined the array we’re testing with:

const letterArray = ["s", "a", "b", "b", "h", "d", "e", "f", "o", "q", "r", "w", "s", "c", "u", "g", "a", "h", "h", "r"];

Then I wrote an arrow function that counts, then sorts, letterArray, before returning the counted and sorted object.

1  const countedAndSortedLetters = (array) => {
2 const unsortedCounts = {};
3 array.forEach((letter) => {
4 if (unsortedCounts[letter]) {
5 unsortedCounts[letter] += 1;
6 } else {
7 unsortedCounts[letter] = 1;
8 }
9 })
10 const sortedCounts = {};
11 Object.keys(unsortedCounts).sort().forEach((key) => {
12 sortedCounts[key] = unsortedCounts[key];
13 })
14 return sortedCounts;
15 }

I then call the arrow function to return the value in my console with:

console.log(countedAndSortedLetters(letterArray));

And get the result:

{ a: 2, b: 2, c: 1, d: 1, e: 1, f: 1, g: 1, h: 3, o: 1, q: 1, r: 2, s: 2, u: 1, w: 1 }

Let’s break this one down:

  • I set a constant, countedAndSortedLetters, to the value returned by a function on line 1. I pass in array as an argument again, and declare an empty object, unsortedCounts, on line 2. Line 1's const countedAndSortedLetters = (array) => { syntax looks funky, but is just a slightly-shorter syntax than const countedAndSortedLetters = function(array) { in this case. At Radial, we frequently work with React, meaning arrow functions' lexical binding of the keyword makes our code easier to read and understand-we don't need the const keyword inside our React classes, and we don't need to call .bind(this) all the time.
  • I would normally use _.forEach or something similar because it tends to handle a lot of errors and JavaScript gotchas gracefully, but instead used JavaScript’s built-in to iterate through the passed-in array on line 3.
  • I personally like using JavaScript’s bracket notation over dot notation for objects because 1. it reminds me of Ruby hashes, and 2. it makes it slightly clear that you’re referencing a value on an object, not calling a function (so I’m not hunting for the () at the end of the function name). Lines 4-7 are more or less the same logic as in Ruby: if the key has a value, increment it by 1; otherwise, set it to 1.
  • JavaScript doesn’t have a great way to sort, or even map, objects (again, Lodash or a similar library is usually very handy here), so instead I define sortedCounts on line 10 as an empty object.
  • I then get the keys from unsortedCounts as an array, sort() them, and forEach() one more time on line 11. This is a place where ES6 syntax really shines, by the way; .forEach((key) => {}) is very clear syntactically about what it is you're doing.
  • Line 12 iterates over the sorted keys and sets that key’s value in sortedCounts.
  • Line 14 tells the overall arrow function to return sortedCounts, which then assigns that value to our countedAndSortedLetters const.

Some notes:

  • I was really feeling the struggle of JavaScript without any helper libraries. node_modules is a monster, but it's also very helpful.
  • I’ve never liked JavaScript’s syntax for prototype functions, like Object.keys. It feels counterintuitive when I'm writing the code to pass a function on Object an instance of itself.
  • It’s more obvious here than in the Ruby example that I’m looping twice-as such, it’s probably also less performant than Ruby’s sort_by, if I had to guess. I may consider revising these to see if I can only loop through once to make a more-performant solution.

My Answer in Java

I used repl.it’s online Java compiler for this, which had me name the file (and therefore the class) Main in this example.

1  import java.util.HashMap;
2
3 public class Main{
4 public static void main(String []args){
5 String[] letterArray = new String[]{"s", "a", "b", "b", "h", "d", "e", "f", "o", "q", "r", "w", "s", "c", "u", "g", "a", "h", "h", "r"};
6 letterCounter(letterArray);
7 }
8
9 private static void letterCounter(String[] letterArray) {
10 HashMap<String, Integer> letterCounts = new HashMap<>();
11
12 for(int i=0; i < letterArray.length; i++) {
13 String letter = letterArray[i];
14 if (letterCounts.containsKey(letter)) {
15 letterCounts.put(letter, letterCounts.get(letter) + 1);
16 } else {
17 letterCounts.put(letter, 1);
18 }
19 }
20 System.out.println(letterCounts);
21 }
22 }

The response is very similar to the JavaScript response:

{a=2, b=2, c=1, d=1, e=1, f=1, g=1, h=3, o=1, q=1, r=2, s=2, u=1, w=1}

Here’s what’s happening this time:

  • I import HashMap on line 1. It's a Java utility, but throws an error when not imported, so I figure it counts as being part of Java's main implementation. It gives me the hash structure I've been using previously.
  • Java throws an error if your class isn’t named what your file is named, so line 3 is a class called Main. I think I'll just let Java be Java here and move on (Repl is great, but it also didn't seem interested in letting me rename the only file).
  • public static void main(String []args){ on line 4 is, as far as I can tell from Oracle's documentation, pretty standard boilerplate for declaring a new class. public means other classes can call this one; static is sort of like self in Ruby in that it's saying it's defining a class method, not an instance method for that class; void clarifies that this method does not return a value; and main is the method name, so we're defining Main.main. (String []args) means that one can pass several strings into the method when called. Interestingly, Main.main throws an error if it returns anything, so this seems to essentially be a good place to call other methods, not a good place to define the main thing we plan to do.
  • Line 5 defines letterArray, as I've been doing. String[] means I'm defining an array of strings, not just one string. I found it confusing that arrays have curly braces {} around them coming from Ruby and JavaScript.
  • Line 6 calls a method called letterCounter with my letterArray argument.
  • Line 9 defines the letterCounter private method. private here appears to achieve the same results as defining methods below the private keyword in Ruby. It's a class method, doesn't return anything (returns void), is called letterCounter, and accepts an array of strings called letterArray.
  • Line 10 continues the trend of declaring everything in Java. In order to make a hash named letterCounts, I need to say that I'm making a HashMap with String keys and Integer values, and call new HashMap() to make it an empty HashMap instance.
  • I used a for loop on line 12, mostly because it was obvious when reading the documentation about it that JavaScript must have pulled this syntax straight from Java. Nice to have one familiar part, at least. As Java and JavaScript devs will doubtlessly know, the syntax here is defining an integer, which is incremented every time you loop through the array until it becomes equal to the array's size. This is one convenience of having arrays start at index 0 rather than 1, you can say < array.length rather than <= array.length.
  • Line 13 was initially String letter = String.valueOf(letterArray[i]) because I had an array of chars rather than Strings which Java refuses to convert into strings unless I specifically tell it to.
  • Lines 14 through 18, again, are pretty much the same logic I’ve used before: to update the letterCounts value at i dependent upon whether it already has a value or not. It was interesting (not good or bad, just odd to my eyes) that Java's HashMaps use .put and .get to set and get values. My brain immediately connected it to the HTTP verbs PUT and GET, which are similar but not the same.
  • Line 20 outputs the resultant letterCounts hash.

Some notes:

  • Java is very, very strict from my perspective, even stricter than JavaScript, which already feels strict to me coming from Ruby. If you don’t tell it exactly what you mean, it will fail, hard.
  • Errors in Java are wonderfully explicit, even to someone as new to the language as I am. In spite of being unfamiliar with the syntax, I was rarely confused about why my code failed. Even when the error thrown confused me (I’d try returning something the method didn’t expect me to return, for example), Java is like Ruby and JavaScript in that it has good documentation from both the maintainers (Oracle, in this case) and the community (a word which here means “Stack Overflow”).
  • There’s a lot of boilerplate in Java. I’m pretty spoiled by Ruby.
  • Java is the only language of the three that gave me exactly what it was I wanted once I played by its rules: the values are sorted all on their own, meaning I didn’t need to loop through the code again, meaning this is probably the most performant of the three letter-sorting methods.
  • Java feels like Ruby’s father who isn’t on speaking terms with Ruby but is mostly cordial at Thanksgiving. It also feels like JavaScript’s estranged stepfather from JavaScript’s mom’s third marriage. I noticed several object-oriented patterns I’m familiar with (and like) from Ruby, but also some syntactical choices that I presume JavaScript went with because it was how Java did it.

Well, this turned out to be a lot more work than I set out to do. But I hope this was informative for how to pull in a bunch of random, unsorted data, put it in a hash, sort it, and pass it along to the next part of your app-I’ve found this very helpful in Rails apps when pushing information over to a Webpack/JavaScript front end.

What improvements would you make to my implementations? Let me know in the comments!

Originally published at https://www.danrice.me on May 19, 2019.

--

--

--

I write about personal finance, career growth, and making the most of the new workforce. You can find my blog at novumopus.com.

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Endpoint Configuration Manager 2103 Tech Preview — HTTP Only site being deprecated

Updating the Mac Pro 5.1 in 2021. Episode 3: Big Sur.

IT Consulting Staten Island

My experience of preparing AZ-900

Expert beginner in software engineering.

Kubernetes WebGui

Searching for Data using FTS — Full Text Search

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Dan Rice

Dan Rice

I write about personal finance, career growth, and making the most of the new workforce. You can find my blog at novumopus.com.

More from Medium

DSA #1: Big O notation Time/Space complexity

Quick Sort (With 3 partitions)

C++ Software developer Interview Q&A — Part 1/2

Why I Decided To Pursue Software Development