On 09.05.2007 21:02, Drew Olson wrote:
> All -
> 
> I've been using ruby for quite some time and I'm only beginning to look
> at python. I really like the way ruby flows as compared to python and I
> can't see myself getting pulled away from ruby. However, there is one
> thing I like about python, and that is the generators. What is the best
> way to translate the following code into ruby? Assume word is some
> string and letters is a string of all the characters a..z:
> 
> [word[0:i]+c+word[i+1:] for i in range(len(word)) for c in letters]
> 
> This is all based on trying to efficiently rewrite
> http://norvig.com/spell-correct.html in ruby. Essentially what this code
> does is get the array of words resulting from inserting every character
> at every possible position in the given word. I find it pretty succinct,
> but I know ruby can do better! I've come up with two ways to do this in
> ruby, but neither seems to "click" with me:
> 
> (0...word.size).inject([]) do |words,i|
>   letters.split('').each do |c|
>     words << word[0...i]+c+word[i..-1]
>   end
>   words
> end
> 
> OR
> 
> (0...words.size).map do |i|
>   letters.split('').map do |c|
>     word[0...i]+c+word[i..-1]
>   end
> end.flatten
> 
> Any advice? Currenty, I'm using the first approach and it's sloooooow
> (I'm assuming inject has high overhead).

Since you are splitting letters all the time, I'd start with pulling out 
this from the loop.  So you could do

LETTERS = "a".."z"

Then, for efficiency reasons, I would not construct the whole thing in 
memory but create an Enumerable class for it

WordGen = Struct.new(:word) do
   include Enumerable

   def each
     word.size.times do |idx|
       WordGen::LETTERS.each do |chr|
         yield word[0...idx] << chr << word[idx..-1]
       end
     end
     self
   end

   def to_a
     map {|x|x}
   end
end

WordGen::LETTERS = "a".."z"

Note also, that you can use "<<" with substrings without affecting the 
original string.  "<<" is more efficient than "+".

Now you can do

wg = WordGen.new "foobar"
wg.each {|w| puts w}
array = wg.to_a
# etc.

Kind regards

	robert