2013-03-16 2 views
3

나는이 데이터를 가지고 :해시 해시에서 특정 키 이름으로 모든 값을 효율적으로 추출하려면 어떻게해야합니까? 현재 내가 사용</p> <pre><code>["[email protected]", "[email protected]", "[email protected]"] </code></pre> <p>:

members = {"total"=>3, "data"=>[ 
    {"email"=>"[email protected]", "timestamp"=>"2013-03-16 01:11:01"}, 
    {"email"=>"[email protected]", "timestamp"=>"2013-03-16 02:07:30"}, 
    {"email"=>"[email protected]", "timestamp"=>"2013-03-16 03:06:24"} 
]} 

과 같은 배열을 생성 할

members['data'].collect { |h| h['email'] } 
  1. 좀 더 효율적인 방법이 있나요 실적과 관련하여 그것을 달성하기 위해?
  2. 달성하기위한 더 짧은 방법이 있습니까?

레일을 사용할 수 있습니다.

답변

3

h['email'] 부분을 네이티브 확장으로 최적화하는 것 외에 위의 예를보다 효율적으로 만들 수있는 방법을 알 수 없습니다. 그렇게하는 것의 효율성 증가는 데이터 세트의 표본 크기가 작을 것입니다. 의심 스럽다면 먼저 데이터를 가져 오거나 파싱하는 I/O를 최적화하는 것보다 훨씬 적습니다.

해시 키를 레이블로 사용하고 문자열이 아닌 데이터 원본에 따라 일반적인 Ruby 관용구이며 메모리 사용 측면에서 더 효율적입니다. 이것은 잠재적으로 효율성면에서 더 큰 이득이며, 데이터를 변환하는 데 많은 노력을 기울일 필요가 없다면 (예 : 주어진 데이터 구조의 특성을 데이터 소스에서 변경하거나, 해시를 변환 할 필요없이 단 한 번 쿼리합니다!)

+0

데이터는 MailChimp API에서 가져온 것입니다. 따라서이 경우 ** 기호 **를 활용할 수 없습니다. 어쨌든 +1 – user569825

2
members = {"total"=>3, "data"=>[ 
    {"email"=>"[email protected]", "timestamp"=>"2013-03-16 01:11:01"}, 
    {"email"=>"[email protected]", "timestamp"=>"2013-03-16 02:07:30"}, 
    {"email"=>"[email protected]", "timestamp"=>"2013-03-16 03:06:24"} 
]} 

temp = members["data"].map{|x|x["email"]} 

당신에게 [ "[email protected]", "[email protected]", "[email protected]"]

을 제공합니다

Difference between map and collect in Ruby?

-

어쩌면 구조체 난 것 당신이 keys으로 symbols를 사용하여 Hash을 구성 할 수 있다면 mProve는 성능

다른 답변에 추가로
Record = Struct.new(:email, :timestamp) 
members = {"total"=>3, "data"=>[ 
    Record.new("[email protected]","2013-03-16 01:11:01"), 
    Record.new("[email protected]","2013-03-16 02:07:30"), 
    Record.new("[email protected]","2013-03-16 03:06:24") 
]} 

temp = members["data"].map(&:email) 

http://blog.rubybestpractices.com/posts/rklemme/017-Struct.html

+0

사실,'map'은'collect' +1보다 짧습니다. +1 : 나는 "더 짧다"라고 말하면서 "덜 복잡합니다"라고 말하면서 - ** block **이없는 변종처럼 말입니다. – user569825

+0

구조체가 관심을 가질 수 있습니다. – ajt

4

, 나는 들어, 값을 수집 할 때 당신이 performance 이득을 가질 수를 추가 할 것 예 :

require 'benchmark' 

members_without_sym = {"total"=>3, "data"=>[ 
    {"email"=>"[email protected]", "timestamp"=>"2013-03-16 01:11:01"}, 
    {"email"=>"[email protected]", "timestamp"=>"2013-03-16 02:07:30"}, 
    {"email"=>"[email protected]", "timestamp"=>"2013-03-16 03:06:24"} 
]} 

members_with_sym = {:total=>3, :data=>[ 
    {:email=> "[email protected]", :timestamp => "2013-03-16 01:11:01"}, 
    {:email=> "[email protected]", :timestamp => "2013-03-16 02:07:30"}, 
    {:email=> "[email protected]", :timestamp=> "2013-03-16 03:06:24"} 
]} 

Benchmark.bm(1) do |algo| 
    algo.report("Without symbol"){ 
    2_000_000.times do 
     members_without_sym['data'].collect { |h| h['email'] } 
    end 
    } 
    algo.report("With symbol"){ 
    2_000_000.times do 
     members_with_sym[:data].collect { |h| h[:email] }  
    end 
    } 
end 

결과 :

 user  system  total  real 
Without symbol 2.260000 0.000000 2.260000 ( 2.254277) 
With symbol 0.880000 0.000000 0.880000 ( 0.878603) 
+0

데이터는 MailChimp API에서 가져온 데이터이므로 ** 기호 **를 활용할 수 없습니다. ** Benchmark ** 클래스를 지적 해 주셔서 감사합니다 - 장래에 유용 할 것입니다! +1 – user569825

+2

기호에 의한 조회와 문자열에 의한 조회가 실제로 훨씬 빠르지 만 벤치 마크에서는이를 증명하지 못합니다.시간 측정에 상당한 지터가 있으며 이와 같이 벤치마킹하려는 무언가의 반복이 의미있는 일은 아닐 것입니다 (사용자 시간이 동일하고 0인지 확인하십시오). 일반적으로 벤치 마크에서 계산의 N 번 반복을 시도해야합니다. 여기서 N은 전반적인 타이밍을 1 초 이상 가져올만큼 충분히 큽니다. 내 컴퓨터에서, 그것은 2M 반복의 순서입니다 :'2_000_000.times {members_without_sym [ 'data']. collect {| h | h [ 'email']}}' – dbenhur

+0

@ dbenhur 지적 해 주셔서 감사합니다. 방금 코드를 업데이트했습니다. – fmendez

관련 문제