RaouL
RaouL

Reputation: 1193

Why can't I modify values of an array in a method?

In the code fragment below, the array deck should equal [6,9,5,6,5,1,2] since Ruby passes arrays by reference. After the method call, the values of deck does not change. Why is that?

def count_cut!(deck)
  s1, s2 = deck[0, deck.last], deck[deck.last..-2]
  deck = s2 + s1 + [deck.last]
end

deck = [5, 1, 6, 9, 5, 6, 2]
count_cut!(deck)
p deck

I am using Ruby 1.9.2-p180.

Upvotes: 3

Views: 2454

Answers (4)

Wayne Conrad
Wayne Conrad

Reputation: 108109

Do it the Ruby way: Instead of modifying the original array, return the modified array:

def count_cut(deck)
  s1, s2 = deck[0, deck.last], deck[deck.last..-2]
  s2 + s1 + [deck.last]
end

The caller then assigns the return value to deck:

deck = [5, 1, 6, 9, 5, 6, 2]
deck = count_cut(deck)
p deck

But consider encapsulating it all in a Deck class, especially if a deck has other behaviors:

class Deck

  def initialize(cards)
    @cards = cards
  end

  def count_cut!
    s1, s2 = @cards[0, @cards.last], @cards[@cards.last..-2]
    @cards = s2 + s1 + [@cards.last]
  end

end

deck = Deck.new [5, 1, 6, 9, 5, 6, 2]
deck.count_cut!
p deck

Upvotes: 5

mu is too short
mu is too short

Reputation: 434785

You're not modifying the array that the deck variable references, you're just assigning a new array to the local variable deck:

deck = s2 + s1 + [deck.last]

The above creates a new array whose contents are s2 + s1 + [deck.last], this new array is then assigned to the local variable deck. The array that deck originally referenced is left unchanged. If you want to change the array, then you'd need something like this:

deck_last = deck.last
deck.clear
deck.push(*s2)
deck.push(*s1)
deck.push(deck_last)

or you'd lose the connection between the local variable deck and the non-local array that it references.

Upvotes: 1

steenslag
steenslag

Reputation: 80085

The .+ method of Array gets you a new Array. Use .unshift to modify the original object.

deck = [1,2,3,4,5]
p deck.object_id #some_number
deck = [6] + deck
p deck.object_id #another_number
deck.unshift([7])
p deck.object_id #unchanged 

Upvotes: 2

Austin Taylor
Austin Taylor

Reputation: 5477

Assigning to deck does not mutate the array that was passed in. It is treated like a local variable in the scope of the function definition. You can call deck.replace if you really want to mutate it.

Upvotes: 8

Related Questions