আমি কীভাবে একটি হ্যাশ থেকে সাব-হ্যাশ উত্তোলন করব?


97

আমার একটি হ্যাশ রয়েছে:

h1 = {:a => :A, :b => :B, :c => :C, :d => :D}

এর মতো সাব-হ্যাশ উত্তোলনের সর্বোত্তম উপায় কী?

h1.extract_subhash(:b, :d, :e, :f) # => {:b => :B, :d => :D}
h1 #=> {:a => :A, :c => :C}



4
@ জনডভোরাক এই প্রশ্নটি কেবল সুভাষ ফেরার বিষয়ে নয়, বিদ্যমান বিদ্যমান সংশোধন সম্পর্কেও। খুব অনুরূপ জিনিস তবে অ্যাক্টিভসপোর্টগুলির সাথে ডিল করার বিভিন্ন উপায় রয়েছে।
স্কালে

উত্তর:


59

আপনি যদি বিশেষত পদ্ধতিটি নিষ্কাশিত উপাদানগুলি ফেরত করতে চান তবে এইচ 1 একই থাকে:

h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
h2 = h1.select {|key, value| [:b, :d, :e, :f].include?(key) } # => {:b=>:B, :d=>:D} 
h1 = Hash[h1.to_a - h2.to_a] # => {:a=>:A, :c=>:C} 

এবং আপনি যদি এটি হ্যাশ শ্রেণিতে প্যাচ করতে চান:

class Hash
  def extract_subhash(*extract)
    h2 = self.select{|key, value| extract.include?(key) }
    self.delete_if {|key, value| extract.include?(key) }
    h2
  end
end

আপনি যদি কেবল হ্যাশ থেকে নির্দিষ্ট উপাদানগুলি সরাতে চান, এটি মুছুন_আইফ ব্যবহার করে অনেক সহজ ।

h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
h1.delete_if {|key, value| [:b, :d, :e, :f].include?(key) } # => {:a=>:A, :c=>:C} 
h1  # => {:a=>:A, :c=>:C} 

4
এটি ও (এন 2) - আপনার বাছাইতে একটি লুপ থাকবে, অন্তর্ভুক্ত থাকাতে অন্য লুপ থাকবে যা h1.size বার বলা হবে।
metakungfu

4
এই উত্তরটি খাঁটি রুবির পক্ষে শালীন, আপনি যদি রেল ব্যবহার করছেন তবে নীচের উত্তরটি (অন্তর্নির্মিত ব্যবহার করে sliceবা exceptআপনার প্রয়োজনের উপর নির্ভর করে) আরও পরিষ্কার
ক্রিয়াস

140

ActiveSupport, 2.3.8 থেকে অন্তত চারটি সুবিধাজনক পদ্ধতি প্রদান করে: #slice, #exceptএবং তাদের ধ্বংসাত্মক প্রতিরূপ: #slice!এবং #except!। এগুলি অন্য উত্তরে উল্লেখ করা হয়েছিল, তবে তাদের এক জায়গায় যোগ করতে:

x = {a: 1, b: 2, c: 3, d: 4}
# => {:a=>1, :b=>2, :c=>3, :d=>4}

x.slice(:a, :b)
# => {:a=>1, :b=>2}

x
# => {:a=>1, :b=>2, :c=>3, :d=>4}

x.except(:a, :b)
# => {:c=>3, :d=>4}

x
# => {:a=>1, :b=>2, :c=>3, :d=>4}

ঠ্যাং পদ্ধতিগুলির রিটার্ন মানগুলি নোট করুন। তারা কেবল বিদ্যমান হ্যাশকেই উপযুক্ত করবে না তবে মুছে ফেলা (রাখা নয়) এন্ট্রিও ফিরিয়ে দেবে। Hash#except!মামলা সেরা উদাহরণ প্রশ্নে দেওয়া:

x = {a: 1, b: 2, c: 3, d: 4}
# => {:a=>1, :b=>2, :c=>3, :d=>4}

x.except!(:c, :d)
# => {:a=>1, :b=>2}

x
# => {:a=>1, :b=>2}

ActiveSupportপুরো রেলগুলির প্রয়োজন হয় না, এটি বেশ হালকা ওজনের। প্রকৃতপক্ষে, প্রচুর নন-রেল রত্নগুলি এর উপর নির্ভর করে, তাই সম্ভবত আপনার এটি ইতিমধ্যে জেমফিল.লকে রয়েছে। নিজের থেকে হ্যাশ ক্লাস বাড়ানোর দরকার নেই।


4
ফল x.except!(:c, :d)(ঠুং সঙ্গে) হওয়া উচিত # => {:a=>1, :b=>2}। আপনার উত্তরটি সম্পাদনা করতে পারলে ভাল।
244 ই

28

আপনি পাগল ব্যবহার করেন তাহলে , হ্যাশ # ফালি যেতে উপায়।

{:a => :A, :b => :B, :c => :C, :d => :D}.slice(:a, :c)
# =>  {:a => :A, :c => :C}

আপনি পাগল ব্যবহার না করা হলে , হ্যাশ # values_at একই আদেশ মান ফিরে আসবে যেমন আপনি তাদেরকে জিজ্ঞেস করেন , যাতে আপনি এটা করতে পারেন:

def slice(hash, *keys)
  Hash[ [keys, hash.values_at(*keys)].transpose]
end

def except(hash, *keys)
  desired_keys = hash.keys - keys
  Hash[ [desired_keys, hash.values_at(*desired_keys)].transpose]
end

প্রাক্তন:

slice({foo: 'bar', 'bar' => 'foo', 2 => 'two'}, 'bar', 2) 
# => {'bar' => 'foo', 2 => 'two'}

except({foo: 'bar', 'bar' => 'foo', 2 => 'two'}, 'bar', 2) 
# => {:foo => 'bar'}

ব্যাখ্যা:

আউট এর {:a => 1, :b => 2, :c => 3}আমরা চাই{:a => 1, :b => 2}

hash = {:a => 1, :b => 2, :c => 3}
keys = [:a, :b]
values = hash.values_at(*keys) #=> [1, 2]
transposed_matrix =[keys, values].transpose #=> [[:a, 1], [:b, 2]]
Hash[transposed_matrix] #=> {:a => 1, :b => 2}

আপনি যদি মনে করেন যে বানরের প্যাচিংটি হ'ল উপায়, আপনি যা চান তা নিম্নলিখিত:

module MyExtension
  module Hash 
    def slice(*keys)
      ::Hash[[keys, self.values_at(*keys)].transpose]
    end
    def except(*keys)
      desired_keys = self.keys - keys
      ::Hash[[desired_keys, self.values_at(*desired_keys)].transpose]
    end
  end
end
Hash.include MyExtension::Hash

4
মোকি প্যাচিং অবশ্যই আইএমও যাওয়ার উপায়। অনেক ক্লিনার এবং অভিপ্রায়কে আরও পরিষ্কার করে তোলে।
রোমেরিও

4
কোরিটলি কোর মডিউলটিকে সম্বোধন করতে কোড পরিবর্তন করতে যুক্ত করুন, মডিউলটি সংজ্ঞায়িত করুন এবং আমদানি প্রসারিত হ্যাশ কোর ... মডিউল কোর এক্সটেনশনগুলি মডিউল হ্যাশ ডিএফ স্লাইস (* কী) :: হ্যাশ [[কী, স্ব.মূল্য_আট (* কী)]। ট্রান্সপোজ] শেষ প্রান্ত শেষ হাশ.কিনেট এক্সটেনশনগুলি :: :: হ্যাশ
রোনান ফগলাস


5

আপনি স্লাইস! (* কী) ব্যবহার করতে পারেন যা অ্যাক্টিভসপোর্টের মূল এক্সটেনশনে উপলব্ধ

initial_hash = {:a => 1, :b => 2, :c => 3, :d => 4}

extracted_slice = initial_hash.slice!(:a, :c)

প্রাথমিক_হ্যাশ এখন হবে

{:b => 2, :d =>4}

প্রত্যাহার_স্লাইড হবে এখন

{:a => 1, :c =>3}

আপনি দেখতে পারেন slice.rb in ActiveSupport 3.1.3


আমি মনে করি আপনি নিষ্কাশন বর্ণনা করছেন!। নির্যাস! প্রারম্ভিক হ্যাশ থেকে কীগুলি সরিয়ে দেয়, মুছে ফেলা কীগুলি সহ একটি নতুন হ্যাশ ফিরিয়ে দেয়। টুকরো! বিপরীত না: সব সরান কিন্তু প্রাথমিক হ্যাশ থেকে নির্দিষ্ট করা কি-সংকলন (আবার, সরানো কী সহ একটি নতুন হ্যাশ ফিরে)। এত টুকরো! এটি "রিটেন" অপারেশনের মতো কিছুটা বেশি।
রাশ ইগান

4
অ্যাক্টিভসপোর্টটি রুবি এসটিআইয়ের অংশ নয়
ভোল্ট

4
module HashExtensions
  def subhash(*keys)
    keys = keys.select { |k| key?(k) }
    Hash[keys.zip(values_at(*keys))]
  end
end

Hash.send(:include, HashExtensions)

{:a => :A, :b => :B, :c => :C, :d => :D}.subhash(:a) # => {:a => :A}

4
সুন্দর চাকরি. তিনি যা চাইছেন তা পুরোপুরি নয়। আপনার পদ্ধতিটি ফিরে আসে: {: d =>: ডি,: বি =>: বি,: ই => নীল,: এফ => নীল} c: সি =>: সি,: এ =>: এ,: ডি => : ডি,: বি =>: বি}
অ্যান্ডি

সমতুল্য এক-লাইন (এবং সম্ভবত দ্রুত) সমাধান: <পূর্ব> def subhash(*keys) select {|k,v| keys.include?(k)} end
শীর্ষে


2

যদি আপনি রেল ব্যবহার করেন তবে এটি হ্যাশ.এক্স্প ব্যতীত সুবিধাজনক হতে পারে

h = {a:1, b:2}
h1 = h.except(:a) # {b:2}

1
class Hash
  def extract(*keys)
    key_index = Hash[keys.map{ |k| [k, true] }] # depends on the size of keys
    partition{ |k, v| key_index.has_key?(k) }.map{ |group| Hash[group] }  
  end
end

h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
h2, h1 = h1.extract(:b, :d, :e, :f)

1

প্রস্তাবিত পদ্ধতির সাথে এখানে দ্রুত পারফরম্যান্স তুলনা #selectকরা দ্রুততম বলে মনে হচ্ছে

k = 1_000_000
Benchmark.bmbm do |x|
  x.report('select') { k.times { {a: 1, b: 2, c: 3}.select { |k, _v| [:a, :b].include?(k) } } }
  x.report('hash transpose') { k.times { Hash[ [[:a, :b], {a: 1, b: 2, c: 3}.fetch_values(:a, :b)].transpose ] } }
  x.report('slice') { k.times { {a: 1, b: 2, c: 3}.slice(:a, :b) } }
end

Rehearsal --------------------------------------------------
select           1.640000   0.010000   1.650000 (  1.651426)
hash transpose   1.720000   0.010000   1.730000 (  1.729950)
slice            1.740000   0.010000   1.750000 (  1.748204)
----------------------------------------- total: 5.130000sec

                     user     system      total        real
select           1.670000   0.010000   1.680000 (  1.683415)
hash transpose   1.680000   0.010000   1.690000 (  1.688110)
slice            1.800000   0.010000   1.810000 (  1.816215)

পরিমার্জনটি এর মতো দেখাবে:

module CoreExtensions
  module Extractable
    refine Hash do
      def extract(*keys)
        select { |k, _v| keys.include?(k) }
      end
    end
  end
end

এবং এটি ব্যবহার করতে:

using ::CoreExtensions::Extractable
{ a: 1, b: 2, c: 3 }.extract(:a, :b)

1

উভয় delete_ifএবং keep_ifরুবি কোর অংশ। এই Hashধরণের প্যাচ না করে আপনি যা চান তা এখানে অর্জন করতে পারেন ।

h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
h2 = h1.clone
p h1.keep_if { |key| [:b, :d, :e, :f].include?(key) } # => {:b => :B, :d => :D}
p h2.delete_if { |key, value| [:b, :d, :e, :f].include?(key) } #=> {:a => :A, :c => :C}

আরও তথ্যের জন্য ডকুমেন্টেশন থেকে নীচের লিঙ্কগুলি দেখুন:


1

অন্যরা যেমন উল্লেখ করেছে, রুবি 2.5 হ্যাশ # স্লাইস পদ্ধতি যুক্ত করেছে।

রেল 5.2.0 বেটা 1 এছাড়াও রুবির পূর্ববর্তী সংস্করণ ব্যবহার করছে এমন কাঠামোর ব্যবহারকারীদের কার্যকারিতা ঝিমিয়ে দেওয়ার জন্য এটি হ্যাশ # স্লাইসের নিজস্ব সংস্করণ যুক্ত করেছে। https://github.com/rails/rails/commit/01ae39660243bc5f0a986e20f9c9bff312b1b5f8

যদি কোনও কারণে আপনার নিজের বাস্তবায়নের সন্ধান করে তবে এটি একটি দুর্দান্ত একটি লাইনারও রয়েছে:

 def slice(*keys)
   keys.each_with_object(Hash.new) { |k, hash| hash[k] = self[k] if has_key?(k) }
 end unless method_defined?(:slice)

0

এই কোডটি আপনি যে কার্যকারিতাটি হ্যাশ শ্রেণিতে জিজ্ঞাসা করছেন তা ইনজেকশন দেয়:

class Hash
    def extract_subhash! *keys
      to_keep = self.keys.to_a - keys
      to_delete = Hash[self.select{|k,v| !to_keep.include? k}]
      self.delete_if {|k,v| !to_keep.include? k}
      to_delete
    end
end

এবং আপনি সরবরাহিত ফলাফল উত্পাদন করে:

h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
p h1.extract_subhash!(:b, :d, :e, :f) # => {b => :B, :d => :D}
p h1 #=> {:a => :A, :c => :C}

দ্রষ্টব্য: এই পদ্ধতিটি আসলে উত্তোলিত কীগুলি / মানগুলি প্রদান করে।


0

এখানে একটি কার্যকর সমাধান রয়েছে যা আপনি যদি রুবি 2.5 তে চালাচ্ছেন না এবং আপনি যদি নতুন পদ্ধতি যুক্ত করে আপনার হ্যাশ শ্রেণিকে কলুষিত করতে চান না তবে সেই ক্ষেত্রে কার্যকর হতে পারে:

slice_hash = -> keys, hash { hash.select { |k, _v| keys.include?(k) } }.curry

তারপরে আপনি এটিকে নেস্টেড হ্যাশগুলিতেও প্রয়োগ করতে পারেন:

my_hash = [{name: "Joe", age: 34}, {name: "Amy", age: 55}]
my_hash.map(&slice_hash.([:name]))
# => [{:name=>"Joe"}, {:name=>"Amy"}]

0

স্লাইস পদ্ধতিতে কেবল একটি সংযোজন, আপনি যদি মূল হ্যাশ থেকে পৃথক করতে চান এমন সুভাষ কীগুলি আপনার পছন্দ মতো করতে পারেন,

slice(*dynamic_keys) # dynamic_keys should be an array type 

0

আমরা কীগুলি লুপ করে এটি করতে পারি কেবলমাত্র আমরা এক্সট্র্যাক্ট করতে চাই এবং কীটি উপস্থিত রয়েছে তা যাচাই করে তারপরে এটি নিষ্কাশন করতে পারি।

class Hash
  def extract(*keys)
    extracted_hash = {}
    keys.each{|key| extracted_hash[key] = self.delete(key) if self.has_key?(key)}
    extracted_hash
  end
end
h1 = {:a => :A, :b => :B, :c => :C, :d => :D}
h2 = h1.extract(:b, :d, :e, :f)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.