2016-06-24 2 views
3

Я читал некоторые различия между < < + =. Но я думаю, что я не понимаю этих различий, потому что мой ожидаемый код не выводит то, что я хочу достичь.Путаница оператора рубина с лопатой (<<) и + =, Контейнерные массивы

в ответ на Ruby differences between += and << to concatenate a string

Я хочу расшифровывать «Кошка» в массив из его букв/слов => [ «с», «ча», «кошка», «а», «в» , «т»]

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") 

Я не понимаю, почему температура < < слова [J] отличается от темпа + = слова [J], когда мне моя логика в данном конкретном случае является правильным.

ответ

3

Отличие заключается в том, что из-<< работ на месте он несколько быстрее, чем +=. Следующий код

require 'benchmark' 

a = '' 
b= '' 

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

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

дает

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

Update

я изначально неправильно понял вопрос. Вот что происходит. Переменные Ruby хранят только ссылки на объекты, а не сами объекты. Вот упрощенный код, который делает то же, что и у вас, и имеет ту же проблему. Я сказал ему напечатать temp и words_array на каждой итерации петель.

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") 

Вот что она печатает:

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"] 

Как вы можете видеть, во время каждой итерации внутреннего цикла после первого, рубин, просто заменив последний элемент из words_array. Это связано с тем, что words_array содержит ссылку на строковый объект, на который ссылаются temp, а << модифицирует этот объект вместо того, чтобы создавать новый объект.

На каждой итерации внешнего контура temp установлен новый объект, и этот новый объект добавляется к words_array, поэтому он не заменяет предыдущие элементы.

Конструкция += возвращает новый объект temp на каждой итерации внутреннего цикла, поэтому он ведет себя так, как ожидалось.

+0

Вы не сравниваете то же самое здесь? –

+0

Спасибо @ sagarpandya82. Я починил это. – lwassink

+0

Я согласен, что использование метода лопаты происходит быстрее, но мне было интересно в моем конкретном случае, почему лопата против + = отличается, потому что логика для меня имеет смысл – DanielSD

2

temp << word[j] изменяет temp на месте;

temp += word[j], который является сокращением для temp = temp + word[j], создает другой объект и присваивает его переменной temp.

КСТАТИ:

input = 'cat'.split('') 
(1..input.length).each_with_object([]) do |i, memo| 
    memo << input.each_cons(i).to_a 
end.flatten(1).map(&:join) 
#⇒ [ 
# [0] "c", 
# [1] "a", 
# [2] "t", 
# [3] "ca", 
# [4] "at", 
# [5] "cat" 
# ] 
2
# this code might be easier to follow 
word = "cat" 

def helper(word) 
    letter_array = [] 
    copy_cat = word 
    word.length.times do 
    starts = 0 
    ends = 0 
    loop do 
     letter_array << copy_cat[starts..ends] 
     ends += 1 
     break if ends == copy_cat.length 
    end 
    copy_cat.delete!(word[0]) 
    end 
    letter_array 
end 

p helper(word) # returns ["c", "ca", "cat", "a", "at", "t"] 
Смежные вопросы