2015-12-04 3 views
1

Допустим, у меня есть пользовательский ввод, который может быть либо это:Элегантный способ в Ruby, чтобы найти первый из возможных ключей соответствия хэш

input = { user_id: 5, ... } 

или это:

input = { app_id: 5, ... } 

И я хочу, чтобы вернуться либо : user_id или: app_id в зависимости от того, какой из них предоставляется. Я могу это сделать:

(input.keys & [:user_id, :app_id]).first 

Есть ли более элегантный, более рубиновый, идиоматический способ сделать это?

Является ли это лучше или хуже, чем выше ?:

input.slice(:user_id, :app_id).keys.first 

(ответы не должны быть строго от Ruby, 2,2 STDLIB, Рельсы методы также приветствуем)

+0

Ваш достаточно элегантный, вауельный вариант использования для набора пересечений. Или вы хотите ** значение ** из хэша, а не ключ? –

+0

Нет, я хочу ключ, а не значение. Благодарю. – Ben

+0

Я могу сделать 'val = input [: user_id] || input [: app_id] 'лично – rainkinz

ответ

4

я бы решить это с другой наоборот, используя find и has_key?:

[:user_id, :app_id].find { |k| input.has_key?(k) } 
+1

Лично я думаю, что это менее элегантно, не изящнее. Независимо от того, что «изящно» означает :) Это кажется более явным, да, но менее кратким. – Ben

+1

@Ben, по крайней мере, он делает меньше ассигнований, поэтому он должен быть более результативным. –

+0

@ D-side, да, хорошая точка, есть дополнительный массив, созданный пересечением. – Ben

1

Ваше решение является достаточно хорошим. Альтернатива, которую я предпочел бы:

input = { app_id: 5, ... } 

KEYS = [:app_id, :user_id, :foo_id] 

input.find { |key, value| KEYS.include? key } 

Таким образом, вы держите what вы хотите отделить от how вы хотите. Вы даже можете назначить KEYS из файла, чтобы вам даже не пришлось открывать код для добавления или удаления ключей из поиска. Но это может быть слишком сложно.

Я искал бы лучшее имя для KEYS жесткое. Именование жестко.

+0

Да, спасибо за предложение. Это просто простой пример, чтобы изолировать код, который я пытаюсь улучшить. Код реального мира более сложный и имеет действительные ключи, определенные в константе Hash. То, что я на самом деле собираю, это адаптер поверх CanCan и Pundit, поэтому я могу использовать либо через один интерфейс. – Ben

+1

Я бы не предпочел это решение, потому что поиск запросов на хэши, как правило, быстрее. Но текущие два ответа являются примером того, как один из способов применяется в разных направлениях. Стоит посмотреть на оба. –

1

Почему не просто:

input.key?(:user_id) ? :user_id : :app_id 

? Я что-то упускаю?

+0

Не масштабируется, что происходит, когда нам нужно искать: foo_id,: bar_id, etc ... – Ben

+0

@Ben, я не понимаю вашу точку зрения. Вы, очевидно, могли бы обернуть его в метод, аргументы которого являются двумя ключами. Это касается всех ответов. –

+0

Я имею в виду, что если нам нужно расширить этот код, чтобы искать дополнительные ключи, троичная структура больше не работает, это уже не два возможных ответа, тогда как некоторые другие ответы здесь будут масштабироваться, просто добавив еще один элемент в массив. .key?() принимает один аргумент, который не может быть массивом, поэтому я не вижу альтернативы при расширении вашего решения, кроме как добавлять дополнительные предложения. – Ben