У меня есть хэш со значениями, это массив. Как удалить повторяющиеся элементы в массиве и соответствующие идентификаторы наиболее эффективным способом?
Вот пример моего хэша
hash = {
"id" => "sjfdkjfd",
"name" => "Field Name",
"type" => "field",
"options" => ["Language", "Question", "Question", "Answer", "Answer"],
"option_ids" => ["12345", "23456", "34567", "45678", "56789"]
}
Идея у меня есть что-то вроде этого
hash["options"].each_with_index { |value, index |
h = {}
if h.key?(value)
delete(value)
delete hash["option_ids"].delete_at(index)
else
h[value] = index
end
}
Результат должен быть
hash = {
"id" => "sjfdkjfd",
"name" => "Field Name",
"type" => "field",
"options" => ["Language", "Question", "Answer"],
"option_ids" => ["12345", "23456", "45678"]
}
Я знаю, что должен учитывать, что когда я удаляю значения параметров и option_ids, индексы этих значений изменяются. Но не уверен, как это сделать
2 ответа
Первая идея, которая у меня возникла, - это сжать значения и вызвать uniq, а затем подумать, как вернуться к исходной форме:
h['options'].zip(h['option_ids']).uniq(&:first).transpose
#=> [["Language", "Question", "Answer"], ["12345", "23456", "45678"]]
h['options'], h['option_ids'] = h['options'].zip(h['option_ids']).uniq(&:first).transpose
h #=> {"id"=>"sjfdkjfd", "name"=>"Field Name", "type"=>"field", "options"=>["Language", "Question", "Answer"], "option_ids"=>["12345", "23456", "45678"]}
Вот шаги:
h['options'].zip(h['option_ids'])
#=> [["Language", "12345"], ["Question", "23456"], ["Question", "34567"], ["Answer", "45678"], ["Answer", "56789"]]
h['options'].zip(h['option_ids']).uniq(&:first)
#=> [["Language", "12345"], ["Question", "23456"], ["Answer", "45678"]]
hash = {
"id" => "sjfdkjfd",
"name" => "Field Name",
"type" => "field",
"options" => ["L", "Q", "Q", "Q", "A", "A", "Q"],
"option_ids" => ["12345", "23456", "34567", "dog", "45678", "56789", "cat"]
}
Я предполагаю, что «повторяющиеся элементы» относятся к смежным равным элементам (2
только в [1,2,2,1]
), а не к «дублированным элементам» (как 1
, так и 2
в предыдущем примере ) . Я показываю, как код будет изменен (фактически упрощен), если будет применена вторая интерпретация.
idx = hash["options"].
each_with_index.
chunk_while { |(a,_),(b,_)| a==b }.
map { |(_,i),*| i }
#=> [0, 1, 4, 6]
hash.merge(
["options", "option_ids"].each_with_object({}) { |k,h| h[k] = hash[k].values_at(*idx) }
)
#=> {"id"=>"sjfdkjfd",
# "name"=>"Field Name",
# "type"=>"field",
# "options"=>["L", "Q", "A", "Q"],
# "option_ids"=>["12345", "23456", "45678", "cat"]}
Если «повторяющиеся элементы» интерпретируются как означающие, что значения "options"
и "option_ids"
должны иметь только первые три элемента, показанные выше, рассчитайте idx
следующим образом:
idx = hash["options"].
each_with_index.
uniq { |s,_| s }.
map(&:last)
#=> [0, 1, 4]
См. Enumerable # chunk_ while (вместо этого можно использовать Enumerable # slice_when) и Array # values_at. Шаги следующие.
a = hash["options"]
#=> ["L", "Q", "Q", "Q", "A", "A", "Q"]
e0 = a.each_with_index
#=> #<Enumerator: ["L", "Q", "Q", "Q", "A", "A", "Q"]:each_with_index>
e1 = e0.chunk_while { |(a,_),(b,_)| a==b }
#=> #<Enumerator: #<Enumerator::Generator:0x000055e4bcf17740>:each>
Мы можем видеть значения, которые перечислитель e1
сгенерирует и передаст map
, преобразовав его в массив:
e1.to_a
#=> [[["L", 0]],
# [["Q", 1], ["Q", 2], ["Q", 3]],
# [["A", 4], ["A", 5]], [["Q", 6]]]
Продолжая ,
idx = e1.map { |(_,i),*| i }
#=> [0, 1, 4, 6]
c = ["options", "option_ids"].
each_with_object({}) { |k,h| h[k] = hash[k].values_at(*idx) }
#=> {"options"=>["L", "Q", "A", "Q"],
# "option_ids"=>["12345", "23456", "45678", "cat"]}
hash.merge(c)
#=> {"id"=>"sjfdkjfd",
# "name"=>"Field Name",
# "type"=>"field",
# "options"=>["L", "Q", "A", "Q"],
# "option_ids"=>["12345", "23456", "45678", "cat"]}
Похожие вопросы
Новые вопросы
ruby
Ruby - это многоплатформенный динамический объектно-ориентированный интерпретируемый язык с открытым исходным кодом. Тег [ruby] предназначен для вопросов, связанных с языком Ruby, включая его синтаксис и его библиотеки. Вопросы Ruby on Rails должны быть помечены [ruby-on-rails].