PastaCountry
PastaCountry

Reputation: 137

<< Operator Appending String to List Acting Strange - Ruby

I'm trying to append a string (made up of characters from another string iterated through a for loop) to an array. But for some reason when I output the items of the array in the end they're all off.

Here's my output for the code I have:

r
racecar
a
aceca
c
cec
e
c
a
r
Final list:
racecar
racecar
acecar
acecar
cecar
cecar
ecar
car
ar
r

I tried adding a empty string to the end of my statement like so,

list << string_current + ""

and it seems to fix the problem. Does anyone know why this is?

def longest_palindrome(s)
  n = s.length
  max_string = ""
  max_string_current = ""
  string_current = ""
  list = []
  counter = 0
  for i in (0...n)
    for j in (i...n)
      string_current << s[j]
      # puts "string_current: #{string_current}"
      if is_palindrome(string_current)
        counter += 1
        puts string_current
        list << string_current
      end
    end
    string_current = ""
  end
  puts "Final list:"
  list.each do |item|
    puts "#{item}"
  end
end

def is_palindrome(string)
  for i in (0..string.length/2)
    if string[i] != string[string.length-1-i]
      return false
    end
  end
  return true
end

longest_palindrome("racecar")

I thought that the items in my final list should be idential to those being put into the list during.

list << string_current

Upvotes: 0

Views: 64

Answers (2)

user1934428
user1934428

Reputation: 22217

You could also have fixed it by

list << string_current.dup

but the real problem is your

string_current << s[j]

Try out (for instance in irb) the following example:

list=[]
str='ab'
list << str
str << 'x'
puts list

You will see that the list contains now 'abx', not 'ab'.

The reason is that the list contains an object reference (pointer) to the string, and when you do the str << 'x', you don't create a new object, but modify the existing one, and list hence sees the updated version.

Upvotes: 0

mu is too short
mu is too short

Reputation: 434665

This:

string_current << s[j]

modifies the string in-place. That means that this:

list << string_current

can put a correct string into list and then that string can be modified later.

When you append your blank string:

list << string_current + ""

you're creating a brand new string (string_current + "") and then pushing that new string onto list so you're doing this:

tmp = string_current + ""
list << tmp

A couple simple ways around your problem would be explicitly dup'ing the string:

if is_palindrome(string_current)
  counter += 1
  puts string_current
  list << string_current.dup # <--------------------
end

or using += instead of << on string_current:

for i in (0...n)
  string_current = ''
  for j in (i...n)
    string_current += s[j]

You should also consider replacing your for loops (which are rare in Ruby) with methods from Enumerable. I don't want to go down a refactoring rabbit hole right now so I'll leave that as an exercise for the reader.

Upvotes: 3

Related Questions