The return on an investment in “How” is much less than the return from an investment in “What”.

Learning about “What” concerns itself with things like “what exists?”, “what do people want?” and “what can be done?”. Learning about “How” concerns itself with “how is this done”, “how does that work”, “how do they do that”. Knowledge about “What” leads to answers about “when” and “why”. These kinds of answers lead to leverage which can lead to profit. Learning about “How” is easy but leads only to competition. Anyone can learn “How” to do something, but if they don’t know when or why, then they’ve only positioned themselves to be used like a tool.

Tools are interchangeable so the ones who know “How” are easily swapped around leaving them with no real power over their destiny. Tools can also become obsolete and get replaced by something better. If the only goal is acquiring knowledge about “How” but no research into “What” has been done then good decisions about picking the “How’s” to invest in can’t be made.

To be really useful as an individual or company, it’s knowledge about “What” that is most important.

I was looking through some old code I had written and found this small and cryptic method for converting a number of seconds into a string containing of this format “hh:mm:ss” and I will describe how it works.  First, the code:

def seconds_to_time(secs)
  hms = [3600, 60].inject([secs]) {|x, y| x += x.pop.divmod(y)}
  return hms.map {|y| "%02d" % y}.join(":")
end

This method leverages the behavior of the Enum.inject method and the Numeric.divmod method to creatively convert the seconds into an array containing hours, minutes and seconds. It then utilizes the Enum.map method to join these values into a recognizable time string. Here is some sample output:

puts seconds_to_time(63628)
17:40:28

The inject method is passed in a starting value and on each iteration the return value of the previous iteration is passed again. This parameter is commonly called an accumulator. The accumulator shows up in the provided block as the first block variable called x. The initial value of this accumulator is an array containing the original seconds. The second parameter to the block (y) is the value from the original array that is the focus of the current iteration. In this example y starts out as 3600.

In the first iteration this value is pop’d out of this array and the divmod method is called passing in the first value from the array that inject is being called on. This value is 3600 and represents the number of seconds in one hour. The return value of the divmod method is an array with the integer part as the first position and the remainder as the second position [17, 2428]. Since the original seconds were pop’d from x, x will now be empty and += will cause x to fill up with the 2 values that were returned from divmod. At the end of the first iteration of the inject method the accumulator variable will contain [17, 2428].

In iteration 2 y is set to 60 which is the number of seconds in a minute while x is set to the value of the accumulator from the previous iteration [17, 2428]. 2428 will be pop’d from this array and divmod will be called on this value with a parameter of y. The result of this call is the array [40, 28] which represents the number of minutes in 2428 seconds and the remainder. This array is then appended to x causing it to become [17, 40, 28] which is the end of our second iteration.

Since this is our last iteration the return value for the inject call will be the array [17, 40, 28]. This array is then map’d into an array of strings formatted as 2 digit integers. This step is needed to pad single digit positions with a leading zero. The final step is to call the join method to glue these pieces together with a colon.

This code was recently updated due to some bugs in the original!

I was asked to come up with a quick way of breaking up an array into random groups of a particular size.  I put together this random_groups_of method extension to the Ruby Array class to solve this problem.  The complete code is listed below along with a trivial example.
class Array
  # Useful for breaking down one large array into
  # smaller randomly organized arrays of size 'number'
  # How it's used: list.random_groups_of(4) =>
  # returns [[...],[...]...]
  # When the last left over group is "small" and
  # no_small_groups was set to true then add these
  # items to the other groups.
  def random_groups_of(number, no_small_groups = false)
    randomized = sort_by{ rand }
    groups = []
    if (number && number > 0)
      randomized.each_slice(number) do |slice|
        groups << slice
      end
      if (groups.size > 1 &&
        groups[-1].size < (number/2.0).round &&
        no_small_groups)
          groups.pop.each_with_index do |e, i|
            groups[i % groups.size - 1] << e # round robin
          end
      end
    end
    groups
  end
end

Here is an example of how to use the random_groups_of method

names = ['one',
	'two',
	'three',
	'four',
	'five',
	'six',
	'seven',
	'eight',
	'nine',
	'ten',
	'eleven',
	'twelve',
	'thirteen',
	'fourteen',
	'fifteen',
	'sixteen',
	'seventeen',
	'eighteen',
	'nineteen',
	'twenty',
	'twentyone',
	'twentytwo']

names.random_groups_of(4, true).
  each_with_index do |g, i|
    puts "#{i+1}. #{g.join(", ")}"
  end

The output from this example:

1. thirteen, two, eleven, eighteen, seventeen
2. twenty, three, twentyone, eight, one
3. nine, fifteen, six, ten
4. seven, four, twelve, fourteen
5. sixteen, nineteen, twentytwo, five

Here is the output when the :no_small_groups option is left off or set to false:

1. fifteen, twenty, nineteen, eight
2. two, one, ten, eighteen
3. fourteen, sixteen, three, four
4. thirteen, seven, twentytwo, nine
5. twentyone, twelve, six, seventeen
6. eleven, five

Safari Browser Tip

April 9, 2010

The Safari browser has a shortcut bar where you can dock websites that you visit frequently and I figured out that you can activate these links using the keyboard.  If you press command+1 (apple key plus the number 1) you will activate the shortcut in the first position.  Other shortcuts can be activated using a different number.  In the past I’ve activated this feature by accident and have been annoyed that it happened.  But now that I’ve had time to digest this feature, I’ve figured out a good way to use it.  One of the websites I visit most often is my todo list in basecamp.  If I put a shortcut to this page in position 1 I can easily get to my todo list with a quick keystroke.  Here’s a short video that does a better job of explaining this tip.

I was in a store a week ago and someone in the store commented about how cool my iphone was. I too think it’s still very cool! The original iphone is just so darn useful and durable that I find it hard to justify replacing it with a newer version. The touch screen form factor has proven very durable and the battery continues to deliver adequate power for my needs. I’ve never used a case and all the original functions still work. There are very cool features in the newer models that I’m “missing out on” but to say that this phone is no longer relevant because of these missing features would be a gross over statement. When people ask me about my phone I’m proud to say that I’m still using the original iphone which is now almost 3 years old. If and when I do replace it I plan to jailbreak it and set it up as my google voice phone for use around the house.

If you’ve ever tried to use sql to perform various operations on database tables with millions of records you’ll know first hand how frustrating it can be waiting hours and even days for a single update statement to return.  If you should lose network connectivity or if the server should crash in the middle of one of these long statements, the database nicely rolls back the transaction that it’s been working on for the past 10 hours.  Also there is no way to track the progress of the operation in order to predict how long it will take to execute.  Using Rails ActiveRecord and a small amount of ruby code (in the form of a rake task), these same operations can be performed incrementally, with the added ability to stop, continue and monitor progress.  The database updates may take longer to run but that is a fair tradeoff given the above benefits.  The ruby code will quietly jug away updating records little by little until they are all done.

Here is some sample code demonstrating this technique:

...
task 'zip9toRes' => :environment do
  desc "populate res_count in zip9"
  sql = ActiveRecord::Base.connection();
  #start at a specific db id
  start_id = 701407
  zip7s = Zip7.find(:all,
    :select => 'id, zip',
    :order => 'id',
    :conditions => ['id > ?', start_id])
  zip7s.each do |z|
    sql <<SQL
update zip9 z set res_count =
(select count(*) from residential
  where zip9 = z.zip)
where zip7 = '#{z.zip}'
SQL
    sql.update sql
    show_progress();
    if @@stop
      puts "stopped at #{z.id}"
      break;
    end
  end
end
...

The above task is looping through 1.1 million zip7 records and for each one it’s telling the zip9 table to populate a res_count column for all zip9 rows in that zip7.  There are roughly 60 million zip9 records and for each one we’d like to know how many homes there are.  The residential table contains 124 million address records that are counted to populate the res_count column.

The show_progress method is a neat way to give some indication that the process is still running:

...
def show_progress()
  wheel = ["|", "/", "-", "\\"]
  moveleft = "\033[D"
  print wheel[@@progress_counter % 4], moveleft
  @@progress_counter += 1
  if @@progress_counter % 100 == 0
    print @@progress_counter, ".."
  end
  $stdout.flush()
end
...

The @@stop variable is initially set to false and a couple of traps are setup to trigger this variable to true which causes the long running task to gracefully stop.

...
@@stop = false
trap("INT") {
  stop()
}
trap("TERM") {
  stop()
}

def stop()
  @@stop = true
end
...

Here is a brief video demonstrating the progress indicator:

Progress Indicator

Progress Indicator

This movie requires Adobe Flash for playback.

Follow

Get every new post delivered to your Inbox.