Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

About this user

« Newer Snippets
Older Snippets »
Showing 1-3 of 3 total  RSS 

Permutations of letters in a word

I've been programming for a while but for some reason figuring this out was really hard - it took me 2 and a half hours. Unsurprisingly, the solution is extremely simple...

   1  
   2  #!/usr/bin/ruby
   3  # permute - takes a word and returns all the permutations of the letters in the word
   4  
   5  def permute(word="")
   6    permutations_among(word.split(//))
   7  end
   8  def permutations_among(letters)
   9    permutations = []
  10    if letters.size == 1
  11      permutations << letters.first
  12    else
  13      letters.each_with_index do |letter, i|
  14        surrounding_letters = letters.dup; surrounding_letters.delete_at(i)
  15        permutations += permutations_among(surrounding_letters).map {|permutation| letter + permutation }
  16      end
  17    end
  18    permutations
  19  end
  20  
  21  permute(ARGV.shift).each {|permutation| puts permutation }


Some benchmarks against other implementations:

* Array#permutations: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/32844
* Array#perm: http://blade.nagaokaut.ac.jp/~sinara/ruby/math/combinatorics/array-perm.rb
* geta: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/139290
* String#perm (based on geta)
* Array#each_permutation: http://knanshon.blogspot.com/2006/08/ruby-permutations.html
* permutation: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/140345


user system total real
permutations_among: 1.680000 0.010000 1.690000 ( 1.700779)
Array#permutations: 1.740000 0.010000 1.750000 ( 1.798288)
geta: 2.430000 0.010000 2.440000 ( 2.506668)
String#perm: 2.260000 0.010000 2.270000 ( 2.280652)
Array#each_permutation: 0.820000 0.000000 0.820000 ( 0.827463)
permutation: 2.140000 0.010000 2.150000 ( 2.171966)


Benchmark code:

   1  
   2  require 'benchmark'
   3  
   4  N = 1_000
   5  Benchmark.bm(40) do |x|
   6    letters = %w(a b c d e)
   7    string = "abcde"
   8    x.report("permutations_among:") do
   9      N.times { permutations_among(letters) }
  10    end
  11    x.report('Array#permutations:') do
  12      N.times { letters.permutations }
  13    end
  14    x.report('geta:') do
  15      N.times { geta(string) }
  16    end
  17    x.report('String#perm:') do
  18      N.times { string.perm }
  19    end
  20    x.report('Array#each_permutation:') do
  21      N.times { letters.each_permutation {|perm| } }
  22    end
  23    x.report('permutation:') do
  24      N.times { 0.upto(string.length.factorial-1) {|i| permutation(string, i)} }
  25    end
  26  end


So, not bad for a first try ;)

String.random

   1  
   2  class String
   3    def self.random(length=20)
   4      chars = ('a'..'z').to_a + ('A'..'Z').to_a + ("0".."9").to_a
   5      hash = ""; length.times { hash << chars[rand(chars.size)] }; hash
   6    end
   7  end

Perform a Rails find() and iterate over the resulting records in groups

   1  
   2  module ActiveRecord
   3    class Base
   4      # This method lets you iterate over the results of a .find, in groups.
   5      # (Basically an interface to LIMIT.)
   6      # Anything you can pass as options to .find, you can pass here. 
   7      # Example 1:
   8      #   Order.each_by(100, :conditions => { :cc_processed_at => nil }) do |order|
   9      #     # do stuff with order
  10      #   end
  11      # Example 2:
  12      #   Person.each_by(50, :order => 'name') do |person, index|
  13      #     # do stuff with person and index
  14      #   end
  15      # Pass :update => true in the options to print a message before each group is
  16      # fetched from the db.
  17      #
  18      # Author: Elliot Winkler <elliot.winkler@gmail.com>
  19      # Source: http://snippets.dzone.com/posts/show/5461
  20      def self.each_by(group_size, options={}, &blk)
  21        update = options.delete(:update) || false
  22        num_records = count(options.except(:from))
  23        return 0 if num_records == 0
  24        #raise "Number of records: #{num_records}"
  25        also_pass_offset = (blk.arity == 2)
  26        0.step(num_records, group_size) do |offset|
  27          find_options = { :offset => offset, :limit => group_size }.merge(options)
  28          if update
  29            if num_records == 1
  30              puts ">> Reading the only record."
  31            else
  32              start_offset = offset + 1
  33              end_offset   = offset + group_size
  34              end_offset   = num_records if num_records < end_offset
  35              puts ">> Reading records #{start_offset}-#{end_offset}."
  36            end
  37          end 
  38          find(:all, find_options).each do |record|
  39            also_pass_offset ? blk.call(record, offset) : blk.call(record)
  40          end
  41        end
  42        num_records
  43      end
  44    end
  45  end


Also see:

* http://weblog.jamisbuck.org/2007/4/6/faking-cursors-in-activerecord
* http://weblog.jamisbuck.org/2007/2/28/poor-man-s-pagination
« Newer Snippets
Older Snippets »
Showing 1-3 of 3 total  RSS