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

Paul McKibbin

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

Random key from Ruby Hash (even faster)

I came across baby's code and then aiosup's from 2 years ago, and realized that I like the simplicity of one and the approach of the other. Kudos to both authors, and I found a way to combine the two approaches into one neat mechanism. More of my ruby here,

   1  
   2  class Hash
   3    @keys_not_used = nil
   4  
   5    def random_key
   6            @keys_not_used = self.dup if (!@keys_not_used or @keys_not_used.size == 0)
   7  	  key = @keys_not_used.keys[rand(@keys_not_used.size)]
   8  	  @keys_not_used.delete(key)
   9            key
  10    end
  11  
  12  end

Odds based random number generator

Worthy of a snippet in its own right as well as a smaller part of this snippet. Full detail on its use is here, but it is a way of returning a random true or false based on the odds.

   1  
   2  class Odds
   3    def self.true?(chance=0)
   4      (rand(chance)<1)
   5    end
   6  end


For example for 1 in 4 odds you would call
   1  
   2    Odds.true?(4)


For a dead cert true? or true?(0) would always return true. Check out the other links for a slightly modified version which is optimised for known low failure rates.

Embedding optional values into strings

I recently wrote a sentence generator, and one of the techniques I worked out might be useful to other people. The full detail is here, but the short version is:

   1  
   2  NAMES=["Paul","Mac","Bimbo","a gamekeeper"]
   3  NOUNS=["hat","monkey","lightbulb","fridge magnet","television"]
   4  ADJECTIVES=["lively","hot","sneaky","elfin","average"]
   5  
   6  def self.true?(chance)
   7    (chance==0 or rand(chance)<1)
   8  end
   9  
  10  def self.build(string_array,chance=0)
  11    true?(chance) ? string_array[rand(string_array.length)] : ""
  12  end
  13  
  14  def self.noun(chance=0)
  15    build(NOUNS, chance)
  16  end
  17  
  18  def self.adjective(chance=0)
  19    build(ADJECTIVES, chance)
  20  end
  21  
  22  def self.name(chance=0)
  23    build(NAMES, chance)
  24  end
  25  
  26  def self.normalize(msg)
  27    while msg.include?("  ")
  28      msg.gsub!(/  /," ")
  29    end
  30    msg
  31  end

What does this all mean. Well, if you want to have conditional random words inserted into a sentence, for example if you are playing madlibs, or generating Fnords, all you have to do to generate the sentence is:
   1  
   2  normalize("#{name} is a #{adjective(5)} #{adjective(2)} #{noun}.")

The numbers in brackets denote the odds of that part of speech being returned. This is used by the true? method to decide success or failure, and by the build method to determine whether a string or an empty string is returned. Finally, the normalize takes two spaces and replaces them with a single space.

Fast Duplicate extraction from an array

Whilst creating a natural language parser, one of the things I was presented with was multiple merged dictionaries, which needed some processing. I was asked to supply a list of duplicated words back, and after trawling the web finding slow code, I decided that going the fast, but inefficient (in terms of space) was the way to go.
The object is to return an array of just those elements that are duplicated in as little time as possible, from a 50,000 word list. One sort and one lookup per element was what I came up with

   1  
   2  array=["long","array","with","lots","and","lots","and","lots","of","array","duplicates","long","and","array"]
   3  arr2=array.sort
   4  arr3=[]
   5  arr4=[]
   6  arr2.each { |a| (arr3[-1]==a) ? (arr4[-1]!=a) ? arr4 << a : "" : arr3 << a }
   7  arr3 => ["and","array","duplicates","long","lots","of","with"]
   8  arr4 => ["and","array","long","lots"]


If you are sure that there are fewer duplicates in the returned array of just duplicated elements, you can remove the arr4 checks at the expense of a final .uniq! pass. i.e.

   1  
   2  array=["long","array","with","lots","and","lots","and","lots","of","array","duplicates","long","and","array"]
   3  arr2=array.sort
   4  arr3=[]
   5  arr4=[]
   6  arr2.each { |a| (arr3[-1]==a) ? arr4 << a : arr3 << a }
   7  arr4.uniq!
   8  
   9  arr3 => ["and","array","duplicates","long","lots","of","with"]
  10  arr4 => ["and","array","long","lots"]


Filtering based on a has_and_belongs_to_many association

To create an indexed view of either all of the items (in a normal index view), or filtered based on an association, you can do the following. For example, if you have a many to many relationship between "users" and "tags", and you wish an index view of users filtered on whether they contain a particular tag, you can do the following:

In the tag index view:
   1  
   2  <h1>Listing tags</h1>
   3  
   4  <table>
   5    <tr>
   6      <th>Name</th>
   7    </tr>
   8  
   9  <% for tag in @tags %>
  10    <tr>
  11      <td><%=h tag.name %></td>
  12      <td><%= link_to 'Users', user_path(:tag_id=>tag) %></td>
  13      <td><%= link_to 'Show', tag_path(tag) %></td>
  14      <td><%= link_to 'Edit', edit_tag_path(tag) %></td>
  15      <td><%= link_to 'Destroy', tag_path(tag), :confirm => 'Are you sure?', :method => :delete %></td>
  16    </tr>
  17    <% end %>
  18  </table>
  19  <br />
  20  <%= link_to 'New tag', new_tag_path %>


Note that
   1  user_path(:tag_id=>tag)
translates to
   1  <a href="/users?tag_id=1">Users</a>
.

In the controller for users, modify the index and change the standard @users=User.find(:all) to

   1  
   2      @tag=Tag.find(params[:tag_id]) if params[:tag_id]
   3      @users = @tag.users || throw rescue User.find(:all)


The
   1  throw rescue
was because the @tag.users could throw an exception as well as having a nil value, and this is DRYer than coding it as
   1  
   2      @users = @tag.users || User.find(:all) rescue User.find(:all)


Full details at Displaying a subset of items from an association.

XML attributes to database columns

I recently needed to update a database with the contents of an XML file under a controlled environment (details at Blackrat's Blog) and came up with this.

With an XML input file of the following format
   1  
   2  <tags>
   3    <tag name='test' desc='Test Description' other='Other Item' />
   4    <tag name='test2' desc='2nd Test Description' other='Another Item' />
   5  </tags>


and a database which contains identical columns name,desc,other (or a superset of the tags) you can use the follow snippet to populate it.

View [import_xml.rhtml]
   1  
   2  <h1>Import XML</h1>
   3  
   4  <%= form_tag({ :action => 'import_xml'}, { :multipart => true }) %>
   5  <%= file_field 'document', 'file' %>
   6  <%= submit_tag 'Import' %>
   7  <%= end_form_tag %>


Controller [names_controller.rb]
   1  
   2  def import_xml
   3    require 'rexml/document'
   4    file=params[:document][:file]
   5    doc=REXML::Document.new(file.read)
   6    doc.root.each_element('//tag') do |tag|
   7      @name = Name.new
   8      @name.update_attributes(tag.attributes)
   9    end
  10    redirect_to :action => 'list'
  11  end

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