Situation:
I have two arrays, secret_code and guess.secret_code = [2, 4, 6, 8] guess = [8, 4, 6, 2]I need to count how many values in the guess array that matches the values and the positions in the secret_code. So for the example above, my method should return 2 because 4 and 6 matches the values and position. 2 and 8 only match the values, but not the positions, so they don't count. This is what the test looks like.
describe MastermindRules do it "counts the exact match when there exact match and value match" do secret_code = [2, 4, 6, 8] guess = [8, 4, 6, 2] MastermindRules.new.exact_match(secret_code, guess).should == 2 end endThis is the method api:
class MastermindRules def exact_match(secret_code, guess) end endSo how many ways can I write the exact match method? Let's find out!
while loop
def exact_match(secret_code, guess) exact_match = 0 index = 0 while index < secret_code.size exact_match += 1 if secret_code[index] == guess[index] index += 1 end exact_match end
until loop
def exact_match(secret_code, guess) exact_match = 0 index = 0 until index >= secret_code.size exact_match += 1 if secret_code[index] == guess[index] index += 1 end exact_match endNote that the condition statement is different than the while loop. In the while loop, it says, execute the loop while index is less than secret_code.size. But for the until statement, it says, execute the loop until the index is greater or equal the the code size. Which one do you choose? I prefer the one that is easier to understand. For example, if I have a method call game.over? I would use until game.over? because while sounds a little clunky, while !game.over?. On the other hand, if I have a method call game.in_progress? I would use while game.in_progress? but not until !game.in_progress?. In this case, if I have to choose between while and until, I would choose while.
loop loop
def exact_match(secret_code, guess) exact_match = 0 index = 0 loop do break if index >= secret_code.size exact_match += 1 if secret_code[index] == guess[index] index += 1 end exact_match endAll of these feel a little clunky don't they? I have to initialize the index and manually increment it. The good thing I learned about Ruby is that if it feels clunky, there's probably a better way to write it.
for loop
def exact_match(secret_code, guess) exact_match = 0 for index in 0...secret_code.size exact_match += 1 if secret_code[index] == guess[index] end exact_match endNote there are three periods for 0...secret_code.size. This gives me a range from 0 to secret_code.size, not including the code size which for me means 0-3. If there are two periods, then the range is 0-4. The two periods will make my test fail because secret_code[4] = nil and guess[4] = nil, which means my exact_match count will be 3. But I don't want that. So be careful with ranges. At the same time, I can also specify an array to loop through. However, this is not flexible for our case because we can't change the secret_code size on the fly.
def exact_match(secret_code, guess) exact_match = 0 for i in [0, 1, 2, 3] exact_match += 1 if secret_code[i] == guess[i] end exact_match end
each_with_index
def exact_match(secret_code, guess) exact_match = 0 secret_code.each_with_index do |value, index| exact_match += 1 if secret_code[index] == guess[index] end exact_match end
range with each
def exact_match(secret_code, guess) exact_match = 0 (0...secret_code.size).each do |index| exact_match += 1 if secret_code[index] == guess[index] end exact_match end
times
def exact_match(secret_code, guess) exact_match = 0 (secret_code.size).times do |index| exact_match += 1 if secret_code[index] == guess[index] end exact_match end
upto
def exact_match(secret_code, guess) exact_match = 0 0.upto(secret_code.size-1) do |index| exact_match += 1 if secret_code[index] == guess[index] end exact_match end
step
def exact_match(secret_code, guess) exact_match = 0 0.step(secret_code.size, 2) do |index| exact_match += 1 if secret_code[index] == guess[index] end exact_match endAs the name suggest, step is probably better when you want to skip elements in an array, but not when you need to loop through each element.
So with all these looping options, which one do you choose? It's really up to you. I prefer the one that best expresses my intent. For my problem, I chose each_with_index because when I read this, I know that the value and the index is important.
For more details, Alan has a great article on loops in ruby.
0 comments:
Post a Comment