루비: 해시 키를 필터링하는 가장 쉬운 방법은?
다음과 같은 해시가 있습니다.
params = { :irrelevant => "A String",
:choice1 => "Oh look, another one",
:choice2 => "Even more strings",
:choice3 => "But wait",
:irrelevant2 => "The last string" }
그리고 선택+int가 아닌 모든 키를 거부할 수 있는 간단한 방법을 원합니다.선택1 또는 선택1 ~ 선택10일 수 있습니다.다양합니다.
단어 선택과 숫자 또는 숫자 뒤에 오는 키를 어떻게 구분합니까?
보너스:
해시를 탭(\t)을 구분 기호로 사용하는 문자열로 변환합니다.저는 이것을 했지만, 그것은 몇 줄의 코드를 필요로 했습니다.보통 루비치안의 달인들은 한 줄 정도로 그것을 할 수 있습니다.
원본 답변으로 편집: 이 답변이 선택된 답변임에도 불구하고(이 의견을 제시한 시점 기준) 이 답변의 원본 버전은 구식입니다.
저는 제가 했던 것처럼 다른 사람들이 이 답변에 의해 소외되는 것을 방지하기 위해 여기에 업데이트를 추가합니다.
다른 답변에서 언급했듯이, Ruby >= 2.5는 다음을 추가했습니다.Hash#slice
이전에는 레일즈에서만 사용할 수 있었던 방법입니다.
예:
> { one: 1, two: 2, three: 3 }.slice(:one, :two)
=> {:one=>1, :two=>2}
편집 종료.다음은 Ruby < 2.5에 Rails가 없는 경우 유용할 것으로 생각되는 원래 답변입니다. 이 시점에서 이 경우는 매우 드물 것으로 생각됩니다.
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]
Ruby에서 Hash#select는 올바른 옵션입니다.Rails로 작업하는 경우 Hash#slice와 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}
가장 쉬운 방법은 다음을 포함하는 것입니다.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"}
버그가 있을 수 있는 다른 기능을 선언하는 것은 가치가 없다고 생각하며, 지난 몇 년 동안 수정된 방법을 사용하는 것이 좋습니다.
레일 관련 작업을 수행하고 별도의 목록에 키가 있는 경우*
표기법:
keys = [:foo, :bar]
hash1 = {foo: 1, bar:2, baz: 3}
hash2 = hash1.slice(*keys)
=> {foo: 1, bar:2}
다른 답변에서 언급한 것처럼 다음을 사용할 수도 있습니다.slice!
해시를 수정하고 지워진 키/값을 반환합니다.
{ a: 1, b: 2, c: 3, d: 4 }.slice(:a, :b)
# => {:a=>1, :b=>2}
# If you have an array of keys you want to limit to, you should splat them:
valid_keys = [:mass, :velocity, :time]
search(options.slice(*valid_keys))
가장 쉬운 방법은 gem 'active support'(또는 gem 'active_support')를 포함하는 것입니다.
params.slice(:choice1, :choice2, :choice3)
이것은 완전한 원래 질문을 해결하기 위한 한 줄입니다.
params.select { |k,_| k[/choice/]}.values.join('\t')
해결하는 것입니다.slice
또단 순는 regexp.
런타임에 교환 가능한 간단하고 복잡한 사용 사례에 적합한 또 다른 접근 방식이 있습니다.
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"
포함:
params = params.select { |key, value| /^choice\d+$/.match(key.to_s) }
나머지 해시를 원하는 경우:
params.delete_if {|k, v| ! k.match(/choice[0-9]+/)}
아니면 그냥 열쇠를 원한다면,
params.keys.delete_if {|k| ! k.match(/choice[0-9]+/)}
이것을 이니셜라이저에 넣습니다.
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"}
params.select{ |k,v| k =~ /choice\d/ }.map{ |k,v| v}.join("\t")
보너스 질문의 경우:
에서 출력이
#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")
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"}
저도 비슷한 문제가 있었습니다. 제 경우 솔루션은 키가 기호가 아니더라도 작동하는 하나의 라이너였지만 기준 키를 배열에 포함시켜야 합니다.
criteria_array = [:choice1, :choice2]
params.select { |k,v| criteria_array.include?(k) } #=> { :choice1 => "Oh look another one",
:choice2 => "Even more strings" }
다른 예
criteria_array = [1, 2, 3]
params = { 1 => "A String",
17 => "Oh look, another one",
25 => "Even more strings",
49 => "But wait",
105 => "The last string" }
params.select { |k,v| criteria_array.include?(k) } #=> { 1 => "A String"}
언급URL : https://stackoverflow.com/questions/7430343/ruby-easiest-way-to-filter-hash-keys
'programing' 카테고리의 다른 글
asp: 텍스트 상자에 힌트를 넣는 방법 (0) | 2023.05.31 |
---|---|
Flutter 및 Android Studio를 설치한 후 "cmdline-tools 구성 요소가 없습니다" 오류가 발생합니다.안드로이드 SDK를 추가했습니다.어떻게 해결할 수 있을까요? (0) | 2023.05.31 |
전용 시스템의 Azure SQL 데이터베이스와 MS SQL Server 비교 (0) | 2023.05.31 |
GitHub 풀 요청을 수행하는 방법 (0) | 2023.05.31 |
레일 3: 랜덤 레코드 가져오기 (0) | 2023.05.31 |