From: Julian Leviston Date: 2013-03-29T10:57:42+09:00 Subject: Re: Translation Project On 29/03/2013, at 7:00 AM, Jeremy Henderson wrote: > Hello all! This is my first post! I started learning Ruby about 3 weeks > ago and have a personal project I would like to do, so I was wondering > if someone could help me out a bit, so I can get it started. > > I would like to have a request made by Ruby to the user for some text. > Then Ruby would take their input and split the text up by every > individual character and assign it a new value based on what letter it > is. > > For instance if: > > "A" = [A,B,C,D,E,F] "B" = [G,H,I,J,K,L] > "C" = [M,N,O,P,Q,R] "D" = [S,T,U,V,W,X,Y,Z] > > So with the info above, Ruby would look at a sentence like, "Hello > World" and it would say, "Ok, "H" is in "B's" array, so it's new value > is "B"... and would do that for each character in the text. Then, when > it's done, it would show the result after it's been put together. So the > final product would be, "BABBC DCCBA". Spaces being accounted for as > they are shown in the original text. > > If you know how this would be done, I would greatly appreciate your > help. Otherwise, if you know a portion of how it might work, I would > appreciate that as well. I'm grateful for any help anyone could provide. > > Thank you > > Hi Jeremy, Ruby is a very concise and expressive programming language. It's possible to pack a lot of code in a short number of lines. Thus, while this code that I wrote as a solution to your problem solves your problem, it's necessary to explain what it does. input = "hello" dict = {a: "abcdef", b: "ghijkl", c: "mnopqr", d: "stuvwxyz"} puts input.each_char.map do |char| key, value = dict.detect{|key, value| value.include?(char)} end.join Here is an annotated version: # set the input string to "hello" input = "hello" # create a Ruby Hash (also called a dictionary in some languages) and set it to the variable dict. # we are using single letter strings for keys, and those keys are then defined by a string with a series of letters in each. # Commas separate the key-value pairs, and keys are separated by values by => # thus, if we were to ask dict for what it defines as "a", we'd get back "abcdef" # We can do this by saying dict["a"] and ruby will then return "abcdef" # I suggest you read up on the Hash class and ruby hashes. They're very powerful and interesting. dict = {"a" => "abcdef", "b" => "ghijkl", "c" => "mnopqr", "d" => "stuvwxyz"} # this is an iterator - ie a loop. It's actually a reasonably complex one because I've chained two together. # input.each_char will give an Enumerator, which effectively gives us the equivalent of an Array (a list) that has # in it a series of strings, each with just one character in it. In other words, it will yield to us a series of items, each which # is one single character string out of the "input" string. # input.each_char.map is equivalent to setting a variable to input.each_char and then sending that variable # the map message. # # now, map is a method that takes some enumerable object such as Array or Enumerator, and evaluates # a chunk of code (called a block in ruby) on each element of that array. I.E. it gives us a new array where each element of the new # array represents the result of evaluating the block of code that is passed to map against each element of the object that map is # called on. # # it's much easier to understand it in examples than it is in explanation # So, this is a good example: # >> ["hello", "this", "is", "fun"].map{|item| item.upcase} # this will yield: # => ["HELLO", "THIS", "IS", "FUN"] # You can see each element of the input array, which is a string with a lowercase word in it, has been "processed" by the block (indicated with {} braces) # in the block {|item| item.upcase}, item represents each element, and then the bit after (item.upcase) is the code that will be executed on each item. # So, in summary, the following code goes through each character as a separate string and assigns it to the variable "char" in the block: # the "puts" call just outputs the result of the input.each_char.map puts input.each_char.map do |char| # now, if we take the next bit in reverse, it'll be more easy to explain. There are three parts to it: # # string objects (in fact most enumerables) have a method called "include?" which basically returns true if it is included # So: # >> "doggie".include?("dog") # => true # should make sense # # Hash or dictionary objects have a method called detect (or find) which is an iterator/enumerator that looks over each # key and value pair, and returns the first pair (as an array) where the block it takes evaluates to true # thus: # >> {"hello" => "goodbye", "yes" => "no"}.detect{|key,value| key == "yes"} # => ["yes", "no"] # ... should come as no surprise # # now, ruby has a way of pulling out values of an array and assigning them to other variables # it's called multiple assignment and this should explain it # >> x,y = [3,4] # => [3, 4] # >> x # => 3 # >> y # => 4 # so, x is 3 and y is 4. # # so what I'm doing in the next line of code is assigning key and value to be the key and value of the first element # of the dict variable whose value includes the char variable's value. key, value = dict.detect{|key, value| value.include?(char)} # that is then returned as the result of the map. At this point, we would be fine to simply put end to mark the end of the map block # (ruby can use {} or do ... end to mark blocks) # but we want to build the single-char strings array into a single string. We do that with join. # ie: # >> ["cool", " beans"].join # => "cool beans" end.join # and that's all! :) # hope that helped! Julian