#ruby-on-rails #ruby
#ruby-on-rails #ruby
Вопрос:
У кого-нибудь есть идеи, почему это не удается?
ree-1.8.7-2011.03 :008 > 3.times.inject({}) {|result, el| result[el.months.ago.strftime("%B")] = "blah"}
IndexError: string not matched
from (irb):8:in `[]='
from (irb):8
from (irb):8:in `inject'
from (irb):8:in `each'
from (irb):8:in `times'
from (irb):8:in `each'
from (irb):8:in `
Комментарии:
1. Вы пробовали упростить код до минимального объема кода, необходимого для демонстрации проблемы?
Ответ №1:
inject
передает возвращаемое значение блока в следующую итерацию, поскольку result
назначение хэша возвращает то, что было назначено. Возврат result
из блока:
3.times.inject({}) {|result, el| result[el.months.ago.strftime("%B")] = "blah"; result }
или используйте each_with_object
, поскольку вы на самом деле не вводите:
3.times.each_with_object({}) {|el, result| result[el.months.ago.strftime("%B")] = "blah" }
Комментарии:
1. @patrick: Обычно вам нужно, только
inject
если вы делаете что-то структурно похожее на накопление total (или если вы находитесь в 1.8 без Rails, где его нетeach_with_object
). И убедитесь, что вы обратили внимание на изменение порядка аргументов для блока при переключении сinject
наeach_with_object
.2. Если вы используете 1.8.x и хотите
each_with_object
(и огромную кучу других вещей 1.9), то отличный backports gem () от Marc-Andre Lafortune[sudo] gem install backports
предоставляет его.3. нет необходимости использовать each_with_object, вы можете написать result.update(ключ => значение) , чтобы обновить накопленный результат хэша.
Ответ №2:
Вероятно, это должен быть комментарий к вашему вопросу, но он был бы довольно нечитаемым, так что вот оно: Enumerable#inject
/ Enumerable#inject
злоупотребляют в сообществе Ruby. В вашем случае вы вводите для создания хэша, но у вас есть хэш.[] для этого:
Hash[(0...3).map { |x| [x.months.ago.strftime("%B"), "blah"] }]
С помощью Facets’mash:
require 'facets'
(0...3).mash { |x| [x.months.ago.strftime("%B"), "blah"] }
С Ruby > = 2.1:
(0...3).map { |x| [x.months.ago.strftime("%B"), "blah"] }.to_h
Комментарии:
1. Использование #reduce вместо #inject ясно показывает, имеет ли смысл ваше применение этого метода в данной проблеме 🙂
2. @samuil: Я не понимаю, что ты имеешь в виду.
3. @Andrew: ужасно, почему? было бы лучше с mash вместо go-backward-Hash[] ? 1 было фигурой речи? 🙂
4. @tokland: должно быть, я отвлекся и забыл проголосовать. Что мне не нравится, так это то, что между
[
и 57 символов]
.5. @Andrew: Хэш […] уродлив, я полностью согласен. Я (и другие) годами проповедовал, чтобы mash был принят в перечислимый Ruby, но Matz это не нравится 🙁 redmine.ruby-lang.org/issues/666 . В каждом языке (в каждом серьезном языке) есть что-то похожее, почему в Ruby этого нет?
Ответ №3:
Потому что возвращаемое значение этого оператора (в блоке) является строкой, а не хэшем. Предполагая, что это то, что вы думали, что делаете 😉
Я только что сделал то же самое на днях, когда не обращал внимания :/
Ответ №4:
Пожалуйста, посмотрите Первый комментарий здесь:
http://blog.purepistos.net/index.php/2008/01/03/ruby-string-not-matched/
Вам нужно убедиться, что возвращаемое значение каждой итерации является вашим хэшем, так как при втором запуске это строка, которую вы назначили на первой итерации.
Также смотрите Здесь:
http://www.ruby-doc.org/core-1.9.2/Enumerable.html#method-i-inject
«каждый элемент в коллекции будет передан именованному методу memo. В любом случае результатом становится новое значение для memo «.
Конкретное сообщение об ошибке, которое вы видите, заключается в том, что оно пытается применить оператор [] к вашей строке, что вызывает сообщение об ошибке.