2012-03-02 30 views
25

Tôi đang cố gắng lấy một tập con của các khóa cho mỗi băm trong một mảng.Làm cách nào tôi có thể lọc một mảng băm để chỉ lấy các khóa trong một mảng khác?

Các băm thực sự lớn hơn nhiều, nhưng tôi figured này là dễ hiểu:

[ 
    { 
    id:2, 
    start: "3:30", 
    break: 30, 
    num_attendees: 14 
    }, 
    { 
    id: 3, 
    start: "3: 40", 
    break: 40, 
    num_attendees: 4 
    }, 
    { 
    id: 4, 
    start: "4: 40", 
    break: 10, 
    num_attendees: 40 
    } 
] 

Tôi muốn có được chỉ các giá trị idstart.

Tôi đã thử:

return_keys = ['id','start'] 
return_array = events.select{|key,val| key.to_s.in? return_keys} 

nhưng điều này trả về một mảng trống.

Trả lời

40

này nên làm những gì bạn muốn:

events.map do |hash| 
    hash.select do |key, value| 
    [:id, :start].include? key 
    end 
end 

có khả năng nhanh hơn (nhưng hơi ít khá) giải pháp:

events.map do |hash| 
    { id: hash[:id], start: hash[:start] } 
end 

Nếu bạn cần return_keys phải năng động:

return_keys = [:id, :start] 
events.map do |hash| 
    {}.tap do |new_hash| 
    return_keys.each do |key| 
     new_hash[key] = hash[key] 
    end 
    end 
end 

Lưu ý rằng, trong mã của bạn, hãy select chọn các phần tử từ mảng, vì đó là những gì bạn gọi nó trên, nhưng không thay đổi băm chứa trong mảng.

Nếu bạn lo ngại về hiệu suất, tôi đã làm chuẩn tất cả các giải pháp được liệt kê ở đây (code):

   user  system  total  real 
amarshall 1 0.140000 0.000000 0.140000 ( 0.140316) 
amarshall 2 0.060000 0.000000 0.060000 ( 0.066409) 
amarshall 3 0.100000 0.000000 0.100000 ( 0.101469) 
tadman 1  0.140000 0.010000 0.150000 ( 0.145489) 
tadman 2  0.110000 0.000000 0.110000 ( 0.111838) 
mu   0.130000 0.000000 0.130000 ( 0.128688) 
+0

Đối với N phím trong 'events' và phím M trong mỗi băm, và các phím P trong mảng nội, điều này thực hiện tại ** O (MNP) ** tốc độ, mà có thể bị tê liệt. – tadman

+1

@tadman Xem câu trả lời cập nhật với giải pháp O (N). –

+0

@tadman Mặc dù, tôi cho rằng nó thực sự là O (NP)? Tôi không nghĩ có gì nhanh hơn thế. Giả sử P là rất nhỏ mặc dù, nó không thực sự ảnh hưởng đến thời gian phức tạp. –

2

Một giải pháp tốt hơn là sử dụng một băm như chỉ số của bạn thay vì làm một mảng tuyến tính tra cứu cho mỗi phím:

events = [{id:2, start:"3:30",break:30,num_attendees:14},{id:3, start:"3:40",break:40,num_attendees:4},{id:4, start:"4:40",break:10,num_attendees:40}] 

return_keys = [ :id, :start ] 

# Compute a quick hash to extract the right values: { key => true } 
key_index = Hash[return_keys.collect { |key| [ key, true ] }] 

return_array = events.collect do |event| 
    event.select do |key, value| 
    key_index[key] 
    end 
end 

# => [{:id=>2, :start=>"3:30"}, {:id=>3, :start=>"3:40"}, {:id=>4, :start=>"4:40"}] 

tôi đã điều chỉnh này để sử dụng những biểu tượng như tên chìa khóa để khớp với định nghĩa lại events.

Điều này có thể được cải thiện hơn nữa bằng cách sử dụng các return_keys như một trình điều khiển trực tiếp:

events = [{id:2, start:"3:30",break:30,num_attendees:14},{id:3, start:"3:40",break:40,num_attendees:4},{id:4, start:"4:40",break:10,num_attendees:40}] 

return_keys = [ :id, :start ] 

return_array = events.collect do |event| 
    Hash[ 
    return_keys.collect do |key| 
     [ key, event[key] ] 
    end 
    ] 
end 

Kết quả là như nhau. Nếu tập con bạn đang trích xuất có xu hướng nhỏ hơn nhiều so với bản gốc, đây có thể là cách tiếp cận tốt nhất.

+1

Trong trường hợp bạn tò mò, tôi đã đánh giá tất cả các giải pháp ở đây và đăng kết quả vào câu trả lời của tôi ':) '. –

28

Nếu bạn tình cờ được sử dụng Rails (hoặc không nhớ kéo trong toàn bộ hoặc một phần của ActiveSupport) sau đó bạn có thể sử dụng Hash#slice:

return_array = events.map { |h| h.slice(:id, :start) } 

Hash#slice hiện một số công việc thêm vào dưới tấm chăn nhưng nó có lẽ là đủ nhanh đến nỗi bạn sẽ không nhận thấy nó vì băm nhỏ và độ trong của nó khá là đẹp.

+5

Thực ra, bạn cần 'require 'active_support/core_ext'' nếu bạn không ở trong Rails. Các phần mở rộng cốt lõi cần được tải một cách rõ ràng vì vậy chỉ cần 'require 'active_support'' không hoạt động. (Tôi nói điều này bởi vì sau này là những gì hầu hết sẽ xem xét "kéo trong tất cả các ActiveSupport".) –

+0

Đối với tốc độ, xem câu trả lời của tôi cho điểm chuẩn ':)'. –

0

Xem xét hiệu quả đó có vẻ là mối quan ngại, tôi sẽ đề xuất những điều sau đây.

require 'set' 

def keep_keys(arr, keeper_keys) 
    keepers = keeper_keys.to_set 
    arr.map { |h| h.select { |k,_| keepers.include?(k) } } 
end 

này sử dụng Hash#select, trong đó, không giống như Enumerable#select, trả về một băm. Tôi đã chuyển đổi keeper_keys thành một bộ để tra cứu nhanh.

Ví dụ

arr = [{ id:2, start: "3:30", break: 30 }, 
     { id: 3, break: 40, num_attendees: 4 }, 
     { break: 10, num_attendees: 40 }] 

keep_keys arr, [:id, :start] 
    #=> [{:id=>2, :start=>"3:30"}, {:id=>3}, {}] 
keep_keys arr, [:start, :break] 
    #=> [{:start=>"3:30", :break=>30}, {:break=>40}, {:break=>10}] 
keep_keys arr, [:id, :start, :cat] 
    #=> [{:id=>2, :start=>"3:30"}, {:id=>3}, {}] 
keep_keys arr, [:start] 
    #=> [{:start=>"3:30"}, {}, {}] 
keep_keys arr, [:cat, :dog] 
Các vấn đề liên quan