Это ожидаемое поведение для набора массивов в Ruby?

Мы делаем небольшую работу в Ruby 1.8.7, которая требует обхода и разбиения неориентированного графа, который странным образом терпит неудачу в рабочей среде. Когда я развожу ошибочный код на самые простые компоненты, я получаю странный провальный тест:

it 'should be able to clear a ruby set of arrays' do
  a = ["2", "b", "d"]
  b = ["1", "a", "c", "e", "f"]
  set = Set.new([a, b])
  a.concat(b)

  p "before clear: #{set.inspect}"
  set.clear
  p "after clear: #{set.inspect}"
  set.size.should == 0
end

Тест не проходит с этим выводом:

"before clear: #<Set: {[\"1\", \"a\", \"c\", \"e\", \"f\"], [\"2\", \"b\", \"d\", \"1\", \"a\", \"c\", \"e\", \"f\"]}>"
"after clear: #<Set: {[\"2\", \"b\", \"d\", \"1\", \"a\", \"c\", \"e\", \"f\"]}>"

expected: 0
     got: 1 (using ==)

Попытки удалить из набора тоже ведут себя странно. Я предполагаю, что Ruby зацикливается на хеш-значениях ключей в массиве, изменяющихся в concat(), но, конечно же, я все равно смогу очистить набор. Верно?


person Nello    schedule 12.06.2012    source источник
comment
В ruby ​​1.9.3p125 нет проблем, как у вас.   -  person megas    schedule 12.06.2012
comment
Я только что нашел это, что отвечает на вопрос об удалении. Но не почему ясно терпит неудачу. stackoverflow.com/questions/10361400/   -  person Nello    schedule 12.06.2012
comment
set.clear использует hash.clear для очистки внутреннего хеша. Hash.clear использует hash.for_each для удаления каждого элемента хеша. Поэтому, если есть ошибка, которая приводит к удалению, она приведет к очистке.   -  person philosodad    schedule 12.06.2012


Ответы (2)


Для этого есть обходной путь: если вы продублируете набор после изменения ключей, новый набор будет иметь обновленные ключи и правильно очищаться. Таким образом, установка set = set.dup решит эту проблему.

person philosodad    schedule 12.06.2012

Подход .dup действительно был моим первым обходным путем, и он работал так, как рекламировалось.

В итоге я добавил в Set следующий обезьяний патч:

class Set
  def rehash
    @hash.rehash
  end
end

что позволяет мне повторно хэшировать ключи набора после любой операции, которая изменяет их хэш-значения.

Кажется, все это исправлено в Ruby 1.9.

person Nello    schedule 13.06.2012
comment
К сожалению, это не работает в JRuby. Для JRuby вы застряли с дублированием набора перед выполнением любых операций, требующих актуальных ключей. - person Nello; 13.06.2012