Swapping array elements using parallel assignment

让人想犯罪 __ 提交于 2019-12-05 15:00:45

It is expected. It follows from how ruby evaluates expressions.

deck[deck.index("A")], deck[deck.index("B")] = deck[deck.index("B")], deck[deck.index("A")]

Implies

deck[deck.index("A")], deck[deck.index("B")] = 'B', 'A'

Note: strings 'A' and 'B' here are for illustration only. Ruby doesn't create new string objects here. Which essentially is:

deck[deck.index("A")] = 'B' -> deck[0] = 'B' (deck = ['B', 'B', 'C'])
deck[deck.index("B")] = 'A' -> deck[0] = 'A' (deck = ['A', 'B', 'C'])

Array#index returns when it finds the first match.

Now,

deck[deck.index("B")], deck[deck.index("A")] = deck[deck.index("A")], deck[deck.index("B")]
-> deck[deck.index("B")], deck[deck.index("A")] = 'A', 'B'
-> deck[deck.index("B")] = 'A' -> deck[1] = 'A' (deck = ['A', 'A', 'C'])
-> deck[deck.index("A")] = 'B' -> deck[0] = 'B' (deck = ['B', 'A', 'C'])

Just as an example, compare the machinations used to search the array, find the correct indexes then swap the values, with what you could do using a Hash:

h = { "cat" => "feline", "dog" => "canine", "cow" => "bovine" }

h['dog'], h['cat'] = h.values_at('cat', 'dog')

h #=> {"cat"=>"canine", "dog"=>"feline", "cow"=>"bovine"}

Now, if Ruby had an assignable values_at= Hash method it could be even cleaner:

h.values_at('dog', 'cat') = h.values_at('cat', 'dog')

but, alas, we don't. Hash slicing is a very powerful tool in Perl and something I miss about Ruby.

And, yes, I know I can add my own assignable values_at=.

M Rajesh is correct, but he actually had to think in order to work it out. I'm too lazy for that!

Here's a printf-debugging way of showing what happened.

deck = ['A', 'B', 'C']
#=> ["A", "B", "C"]
deck[deck.index("A").tap {|index| 
  STDERR.puts "Result of indexing for #{"A".inspect} is #{index.inspect}"
  }], 
deck[deck.index("B").tap {|index| 
  STDERR.puts "Result of indexing for #{"B".inspect} is #{index.inspect}"
  }] = 
deck[deck.index("B")], deck[deck.index("A")]
# Result of indexing for "A" is 0
# Result of indexing for "B" is 0
#=> ["B", "A"]
deck
#=> ["A", "B", "C"]
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!