Обмен элементов массива с использованием параллельного присваивания - PullRequest
4 голосов
/ 15 ноября 2010

Заинтригованный этим вопросом , я немного поиграл с параллельным присваиванием с массивами и вызовами методов. Итак, вот пример парадигмы: попытка поменять местами два члена в массиве по их значению:

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

Массив не изменился. Но если мы изменим порядок аргументов, это сработает:

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

Полагаю, это связано с порядком вызова методов index в присваивании, но я не вижу этого ясно. Может кто-нибудь объяснить, пожалуйста, порядок вещей под ним, и почему первый пример не меняет местами член, а второй делает?

Ответы [ 3 ]

3 голосов
/ 15 ноября 2010

Ожидается. Это следует из того, как ruby ​​оценивает выражения.

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

Подразумевается

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

Примечание: строки «A» и «B» здесь только для иллюстрации. Ruby не создает новые строковые объекты здесь . Что по существу:

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

Массив # index возвращается, когда находит первое совпадение.

Теперь

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'])
1 голос
/ 03 декабря 2010

М Раджеш прав, но он действительно должен был подумать, чтобы решить это. Я слишком ленив для этого!

Вот способ отладки printf, показывающий, что произошло.

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"]
1 голос
/ 15 ноября 2010

В качестве примера сравните махинации, использованные для поиска в массиве, найдите правильные индексы, а затем поменяйте местами значения, что вы могли бы сделать, используя хэш:

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

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

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

Теперь, если бы у Ruby был назначаемый values_at= хэш-метод, он мог бы быть еще чище:

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

но, увы, нет. Хэширование - очень мощный инструмент в Perl, и мне не хватает Ruby.

И, да, я знаю, что могу добавить свой собственный присваиваемый values_at=.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...