Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ruby operator confusion with shovel (<<) and += , Concating arrays

I've read some of the differences between << +=. But i think i may not understand these differences, because my expected code doesn't output what i want to achieve.

in response to Ruby differences between += and << to concatenate a string

I want to unscramble "Cat" into an array of its letters/words => ["c", "ca", "cat", "a", "at", "t"]

def helper(word)
words_array = []
idx = 0
while idx < word.length 
    j = idx  
    temp = ""
    while j < word.length
        **temp << word[j]**
        words_array << temp unless words_array.include?(temp) 
    j += 1 
    end
    idx += 1 
end 
p words_array
end
helper("cat")

I don't understand why temp << word[j] is different from temp += word[j] when to me my logic in this specific case is correct.

like image 789
DanielSD Avatar asked Mar 11 '23 21:03

DanielSD


1 Answers

One difference is that because << works in place it is somewhat faster than +=. The following code

require 'benchmark'

a = ''
b= ''

puts Benchmark.measure {
  100000.times { a << 'test' }
}

puts Benchmark.measure {
  100000.times { b += 'test' }
}

yields

0.000000   0.000000   0.000000 (  0.004653)
0.060000   0.060000   0.120000 (  0.108534)

Update

I originally misunderstood the question. Here's whats going on. Ruby variables only store references to objects, not the objects themselves. Here's simplified code that does the same thing as yours, and has the same issue. I've told it to print temp and words_array on each iteration of the loops.

def helper(word)
  words_array = []

  word.length.times do |i|
    temp = ''
    (i...word.length).each do |j|
      temp << word[j]
      puts "temp:\t#{temp}"
      words_array << temp unless words_array.include?(temp)
      puts "words:\t#{words_array}"
    end
  end

  words_array
end

p helper("cat")

Here is what it prints:

temp:   c
words:  ["c"]
temp:   ca
words:  ["ca"]
temp:   cat
words:  ["cat"]
temp:   a
words:  ["cat", "a"]
temp:   at
words:  ["cat", "at"]
temp:   t
words:  ["cat", "at", "t"]
["cat", "at", "t"]

As you can see, during each iteration of the inner loop after the first, ruby is simply replacing the last element of words_array. That is because words_array holds a reference to the string object referenced by temp, and << modifies that object in place rather than creating a new object.

On each iteration of the outer loop temp is set to a new object, and that new object is appended to words_array, so it doesn't replace the previous elements.

The += construct returns a new object to temp on each iteration of the inner loop, which is why it does behave as expected.

like image 184
lwassink Avatar answered Mar 14 '23 21:03

lwassink