Array.inject
Having had a lot of fun last week doing Uncle Bob's prime factors kata, I've been doing the Codebreaker example from the RSpec book this week. In section 9.2 the number_match_count method is refactored to be
def number_match_count
total_match_count - exact_match_count
end
And the problem of implementing total_match_count is discussed. The book starts with
def total_match_count
count = 0
secret = @secret.split('')
@guess.split('').map do |n|
if secret.include?(n)
secret.delete_at(secret.index(n))
count += 1
end
end
count
end
I didn't like this so in a separate branch I came up with
def total_match_count
total_match_count = 0
secret = @secret.clone # need a copy as we will slice destructively
@guess.each_char do |char|
pos = secret.index(char)
secret.slice!(pos) and total_match_count +=1 if pos
end
total_match_count
end
Which is OK, but fairly similar.
What the RSpec book is leading upto though is
def total_match_count
secret = @secret.split('')
@guess.split('').inject(0) do |count, n|
count + (delete_first(secret, n) ? 1 : 0)
end
end
def
delete_first(code, n) code.delete_at(code.index(n)) if code.index(n)
end
This uses Array.inject, something I have always avoided. This is the second time the book has focused on Array.inject, and I started thinking why the fascination with inject. What is it that Ruby programmers like about it that I'm missing.
Some googling produced
This thread, of which the best bits are:
-
How I remember: Inject takes a binary operation (e.g. +) and injects it between each element of a list. [1,2,3].inject { |a,b| a+b } => 1+2+3 -- Jim Weirich-
... there is a fundamental difference between the inject and each versions. The "each" verison is procedural. It defines state (the value of b) and how that state changes in each iteration (b += a). The "inject" version is functional. There are no extra state variables in our code that need initialization. And the expression itself is the value, rather than having a side effect on a local variable. Not that one way is better than the other, just noting differences. -- Jim Weirich-
So, in math-speak, I think one could say: inject applies a block pairwise as an n-ary operation over an Enumerable, with an optional initial value. -- A LeDonne
Perhaps Array.inject is worth investigating further as a step towards doing more functional programming.
Blogging with Vim
In my attempts to become more proficient with VIM I thought I would try and push some standard editing tasks in its direction. My first choice was blog posting. For this to work I need VIM to:
- Understand that my blog posts are in markdown
- Get and retrieve posts from typo like the textmate blogging bundle does.
As usual with anything VIM things are not easy. Much of this is down to my ignorance, but the steep learning curve VIM never ceases to amaze me with its incline :)
After much googling I came across a vimblog.vim, and was able to get and retrieve posts ... SORT OF
However post retrieval doesn't quite work (partly my fault for using Typo and not Wordpress!) as not all the post is returned when I use a "Continue reading...".
So know I have to learn how to debug vim scripts so I can examine the XML object returned and see if either
- Vimblog is making the wrong call and getting only the article summary rather than the full article
- Vimblog is not extracting the correct field from the XML object
- Something else is going wrong
I guess if VIM really was the editor for me, I would just hack a solution to this. Perhaps I will, but I feel that I've got better things to do than spending tens of hours learning how to script VIM.