У меня есть хеш, который выглядит примерно так:
params = { :irrelevant => "A String",
:choice1 => "Oh look, another one",
:choice2 => "Even more strings",
:choice3 => "But wait",
:irrelevant2 => "The last string" }
И я хочу простой способ отклонить все ключи, которые не являются выбором + int. Это может быть выбор1 или выбор1 по выбору10. Он меняется.
Как выделить ключи только с выбором слова и цифрой или цифрами после них?
Bonus:
Поверните хеш в строку с вкладкой (\ t) в качестве разделителя. Я сделал это, но потребовалось несколько строк кода. Обычно мастера-рубики могут делать это в одной или нескольких строках.
Ответ 1
ПРИМЕЧАНИЕ.. Если вы используете Rails, вы можете использовать Hash.slice
, как указано lfx_cool в ответе ниже.
Если вы используете Ruby, вы можете использовать метод select
. Вам нужно будет преобразовать ключ из символа в строку, чтобы выполнить регулярное выражение. Это даст вам новый хэш только с выбором.
choices = params.select { |key, value| key.to_s.match(/^choice\d+/) }
или вы можете использовать delete_if
и изменить существующий хэш, например.
params.delete_if { |key, value| !key.to_s.match(/choice\d+/) }
или если это только ключи, а не нужные значения, вы можете сделать:
params.keys.select { |key| key.to_s.match(/^choice\d+/) }
и это даст просто массив ключей, например. [:choice1, :choice2, :choice3]
Ответ 2
В Ruby выбор Hash # является правильным вариантом. Если вы работаете с Rails, вы можете использовать кусочек Hash # и Hash # slice!. например (рельсы 3.2.13)
h1 = {:a => 1, :b => 2, :c => 3, :d => 4}
h1.slice(:a, :b) # return {:a=>1, :b=>2}, but h1 is not changed
h2 = h1.slice!(:a, :b) # h1 = {:a=>1, :b=>2}, h2 = {:c => 3, :d => 4}
Ответ 3
Самый простой способ - включить gem 'activesupport'
(или gem 'active_support'
).
Затем в вашем классе вам нужно только
require 'active_support/core_ext/hash/slice'
и вызвать
params.slice(:choice1, :choice2, :choice3) # => {:choice1=>"Oh look, another one", :choice2=>"Even more strings", :choice3=>"But wait"}
Я считаю, что не стоит объявлять другие функции, которые могут иметь ошибки, и лучше использовать метод, который был изменен в течение последних нескольких лет.
Ответ 4
Самый простой способ - включить gem 'activesupport' (или gem 'active_support').
params.slice(:choice1, :choice2, :choice3)
Ответ 5
Это одна строка для решения полного исходного вопроса:
params.select { |k,_| k[/choice/]}.values.join('\t')
Но большинство решений выше решают случай, когда вам нужно заранее знать ключи, используя slice
или простое регулярное выражение.
Вот еще один подход , который работает для простых и более сложных прецедентов, которые можно заменять во время выполнения
data = {}
matcher = ->(key,value) { COMPLEX LOGIC HERE }
data.select(&matcher)
Теперь не только это позволяет более сложную логику согласовывать ключи или значения, но также легче протестировать, и вы можете поменять логику соответствия во время выполнения.
Ex для решения исходной проблемы:
def some_method(hash, matcher)
hash.select(&matcher).values.join('\t')
end
params = { :irrelevant => "A String",
:choice1 => "Oh look, another one",
:choice2 => "Even more strings",
:choice3 => "But wait",
:irrelevant2 => "The last string" }
some_method(params, ->(k,_) { k[/choice/]}) # => "Oh look, another one\\tEven more strings\\tBut wait"
some_method(params, ->(_,v) { v[/string/]}) # => "Even more strings\\tThe last string"
Ответ 6
Поместите это в инициализатор
class Hash
def filter(*args)
return nil if args.try(:empty?)
if args.size == 1
args[0] = args[0].to_s if args[0].is_a?(Symbol)
self.select {|key| key.to_s.match(args.first) }
else
self.select {|key| args.include?(key)}
end
end
end
Затем вы можете сделать
{a: "1", b: "b", c: "c", d: "d"}.filter(:a, :b) # => {a: "1", b: "b"}
или
{a: "1", b: "b", c: "c", d: "d"}.filter(/^a/) # => {a: "1"}
Ответ 7
Если вам нужен оставшийся хэш:
params.delete_if {|k, v| ! k.match(/choice[0-9]+/)}
или если вы просто хотите использовать клавиши:
params.keys.delete_if {|k| ! k.match(/choice[0-9]+/)}
Ответ 8
params.select{ |k,v| k =~ /choice\d/ }.map{ |k,v| v}.join("\t")
Ответ 9
С Hash::select
:
params = params.select { |key, value| /^choice\d+$/.match(key.to_s) }
Ответ 10
Что касается бонусного вопроса:
-
Если у вас есть выход из метода #select
, подобного этому (список из 2-х элементовных массивов):
[[:choice1, "Oh look, another one"], [:choice2, "Even more strings"], [:choice3, "But wait"]]
то просто возьмите этот результат и выполните:
filtered_params.join("\t")
# or if you want only values instead of pairs key-value
filtered_params.map(&:last).join("\t")
-
Если вы используете метод #delete_if
, подобный этому (хэш):
{:choice1=>"Oh look, another one", :choice2=>"Even more strings", :choice3=>"But wait"}
то
filtered_params.to_a.join("\t")
# or
filtered_params.values.join("\t")
Ответ 11
params = { :irrelevant => "A String",
:choice1 => "Oh look, another one",
:choice2 => "Even more strings",
:choice3 => "But wait",
:irrelevant2 => "The last string" }
choices = params.select { |key, value| key.to_s[/^choice\d+/] }
#=> {:choice1=>"Oh look, another one", :choice2=>"Even more strings", :choice3=>"But wait"}