Предположим, у меня есть объект:
obj = Object.new #<Object:0x00007fbe36b4db28>
И я преобразовываю его в перечислитель:
obj_enum = obj.to_enum #<Enumerator: #<Object:0x00007fbe36b4db28>:each>
Теперь я хочу получить свой объект обратно из перечислителя. Я нашел способ сделать это, но он кажется излишне заумным (не говоря уже о довольно fr agile):
extracted_obj = ObjectSpace._id2ref(
obj_enum.inspect.match(/0x[0-9a-f]*/).values_at(0)[0].to_i(16)/2
)
p obj.equal? extracted_obj # => true
В случае, если это не ясно, я проверяю объект Enumerator, используя regex для извлечения идентификатора исходного объекта из результирующей строки, преобразования его в целое число (и деления на 2) и использования ObjectSpace._id2ref
для преобразования идентификатора в ссылку на мой объект. Ужасные вещи.
Мне трудно поверить, что это самый простой способ выполнить эту работу, но некоторые часы поисковика мне ничего не показали. Есть ли простой способ извлечь объект после наложения Enumerator вокруг него с помощью #to_enum
, или это в значительной степени способ сделать это?
Редактировать:
Как говорит Амадан ниже (и высоко ценится, Амадан), это может быть проблемой XY, и мне, возможно, придется пересмотреть свое решение. Я немного объясню, как я сюда попал.
(мета) вариант использования: у меня (переменное) количество объектов в массиве. Каждый из объектов представляет массив целых чисел (все одинакового размера) в качестве атрибута, отсортированного по убыванию. Я хочу итерировать массивы каждого из объектов одновременно, находя объект или объекты с самым высоким целым числом, не совпадающим в массиве другого объекта.
Казалось, что внешняя итерация была хорошим способом go сделать это потому, что одновременная внутренняя итерация нескольких объектов, которые должны знать о промежуточных результатах итераций друг друга, также довольно быстро появляется. Но когда я нашел перечислитель, содержащий объект с массивом с наибольшим значением, мне нужно вернуть объект, который он переносит.
Очень хорошо может быть лучший способ go, чем использование счетчиков, когда это является требованием. Однако фактический процесс итерации и выбора довольно прост при их использовании.
Итак. Применяемый вариант использования: количество покерных рук, у которых рука не лучше, чем у старшей карты. Найдите выигрышную комбинацию. «Выигрышная рука» - это рука с наивысшей картой, не имеющая ранга другой руки. (Костюмы не имеют значения.) Если все карты совпадают в двух или более раздачах, верните эти комбинации в массив.
«Пример минимальной воспроизводимости»:
class Hand
attr_reader :cards
def initialize(cards)
@cards = cards.sort.reverse
end
def each
@cards.each { |card| yield(card.first) }
end
end
class Poker
def initialize(hands)
@hands = hands.map { |hand| Hand.new(hand) }
end
def high_cards
hand_enums = @hands.map(&:to_enum)
loop do
max_rank = hand_enums.map(&:peek).max
hand_enums.delete_if { |enum| enum.peek != max_rank }
hand_enums.each(&:next)
end
hand_enums.map { |e| from_enum(e).cards }
end
def from_enum(enum)
ObjectSpace._id2ref(
enum.inspect.match(/0x[0-9a-f]*/).values_at(0)[0].to_i(16) / 2
)
end
end
hands = [
[[10, "D"], [3, "C"], [8, "C"], [7, "C"], [9, "D"]],
[[10, "D"], [8, "S"], [7, "S"], [9, "H"], [2, "H"]],
[[9, "C"], [8, "H"], [9, "S"], [4, "C"], [7, "D"]]
]
game = Poker.new(hands)
p game.high_cards # => [[[10, "D"], [9, "D"], [8, "C"], [7, "C"], [3, "C"]]]
Это «работает» но я, конечно, согласен с Амаданом, что это взлом Может быть, интересный и поучительный, но все же взломать. TIA для любых предложений.