রুবি: হ্যাশ কীগুলি ফিল্টার করার সহজতম উপায়?


225

আমার একটি হ্যাশ রয়েছে যা দেখতে এরকম কিছু দেখাচ্ছে:

params = { :irrelevant => "A String",
           :choice1 => "Oh look, another one",
           :choice2 => "Even more strings",
           :choice3 => "But wait",
           :irrelevant2 => "The last string" }

এবং আমি পছন্দ করি না এমন সমস্ত কীগুলি প্রত্যাখ্যান করার একটি সহজ উপায় চাই। এটি পছন্দের 1, বা পছন্দ 10 এর মাধ্যমে পছন্দ 1 হতে পারে। নির্ভিওর কএ.

আমি কীভাবে কী শব্দগুলি কেবল শব্দ পছন্দ এবং একটি অঙ্ক বা তার পরে অঙ্কগুলি দিয়ে আউট করব?

বোনাস:

ড্যাশিমিটার হিসাবে হ্যাশটিকে স্ট্রিংয়ে ট্যাব (\ t) দিয়ে পরিবর্তন করুন। আমি এটি করেছি, তবে এটি কোডের বেশ কয়েকটি লাইন নিয়েছে। সাধারণত মাস্টার রুবিশিয়ানরা এটি এক বা এক লাইনে করতে পারেন।


বোনাস প্রশ্নের শর্তাবলী, আপনি স্ট্রিং দেখতে চান কি আপনি তা পরিষ্কার করতে পারেন।
মাইকেজ

অবশ্যই, উপরের উদাহরণটিতে হ্যাশটি উপস্থিত হবে: "ওহ দেখুন, আরও একটি স্ট্রিংয়ের পরে আরও একটি স্ট্রিং wait t অপেক্ষা করুন" (কেবল স্ট্রিংয়ের শেষে নয়, কেবল তাদের মধ্যে)
ডেরেক

মন্তব্যে আপনার উদাহরণের স্ট্রিংটি কেটে দেওয়া হয়েছে। আপনি আপনার প্রশ্ন সম্পাদনা করতে এবং সেখানে উদাহরণ যুক্ত করতে সম্পাদনা লিঙ্কটি ব্যবহার করতে পারেন। আপনি যতটা রুবি নিয়ে এসেছেন তা পোস্ট করতে পারেন যা আপনি অর্জন করতে চান তার উদাহরণ হিসাবে।
মাইকেজ

উত্তর:


281

মূল উত্তরে সম্পাদনা করুন : যদিও এটি উত্তর (এই মন্তব্যের সময় হিসাবে) নির্বাচিত উত্তর হলেও এই উত্তরের মূল সংস্করণটি পুরানো।

আমি অন্যদের মতো এই উত্তরটি দ্বারা বিভ্রান্ত হওয়া এড়ানোর জন্য এখানে একটি আপডেট যুক্ত করছি।

অন্য উত্তরের হিসাবে উল্লেখ করা হয়েছে, রুবি> = 2.5 এ Hash#sliceপদ্ধতিটি যুক্ত করেছিলেন যা আগে কেবল রেলগুলিতে পাওয়া যায়।

উদাহরণ:

> { one: 1, two: 2, three: 3 }.slice(:one, :two)
=> {:one=>1, :two=>2}

সম্পাদনার সমাপ্তি। এর পরে আসল উত্তরটি যা অনুমান করে তা হ'ল আপনি যদি ব্যর্থ না হয়ে রুবি <2.5 তে থাকেন তবে আমি ধারণা করি যে এই মুহুর্তে এই ঘটনাটি বেশ অস্বাভাবিক।


আপনি যদি রুবি ব্যবহার করেন তবে আপনি 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]


1
অসাধারণ! আমি একবার এটি দেখতে, এটি এত সহজ! আপনাকে অনেক ধন্যবাদ, এবং অন্যদেরও ধন্যবাদ যারা উত্তর দেওয়ার জন্য সময় নিয়েছিল।
ডেরেক

2
আজকাল আইআইআরসি-র নিয়মিত অভিব্যক্তিগুলির সাথে প্রতীকগুলি পার্স করা যায়।
অ্যান্ড্রু গ্রিম

@ অ্যান্ড্রু, আমি মনে করি আপনি ঠিক বলেছেন আমি এই প্রশ্নের উত্তরটি পরীক্ষা করার সময় আমি 1.8.7 এ ছিল।
মাইকেজ

1
প্রতিচ্ছবিটি .selectহ'ল .reject, যদি তা আপনার কোডটিকে আরও ইডিয়োমেটিক করে তোলে।
জো আতজবার্গার

#sliceপথ এমনকি activesupport ছাড়া 2.5.3 আমাকে জন্য কাজ করে।
গ্রেওয়াল্ফ

305

রুবিতে, হ্যাশ # নির্বাচন একটি সঠিক বিকল্প। আপনি যদি রেলগুলির সাথে কাজ করেন তবে আপনি হ্যাশ # স্লাইস এবং হ্যাশ # স্লাইস ব্যবহার করতে পারেন। উদাঃ (রেল ৩.২.১৩)

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}

12
স্ট্রিংযুক্ত কীগুলির জন্য নজর রাখুন .. h1 = = 'a' => 1,: b => 2} কেবল h1.slice (: a,: খ)
ডেভিডক্লম

দুর্দান্ত সমাধান। আমি এটি আরএসপিএকে ফলাফল ফেরত দেওয়ার ক্ষেত্রে ব্যবহার করেছি, যেখানে আমি একটি হ্যাশের মধ্যে একটি হ্যাশের একটি মান পার্স করতে চেয়েছিলাম। `` `পরীক্ষা = {: a => ১,: বি => ২, সি => {: এ => ১,: বি => ২}} সমাধান ==> টেস্ট.সি.স্লাইস (: বি)` ` `
প্রিয়াঙ্কা

অ্যাক্টিভসপোর্ট দ্বারা কারাগুলি প্রতিস্থাপন করুন এবং এটি নিখুঁত;)
জেফ্রয়ে

5
এটি যদিও প্রশ্নের উত্তর দেয় না, যেহেতু তিনি "পছন্দ + ইনট" কীগুলির জন্য মানগুলি বের করার একটি উপায় চান। আপনার সমাধানটি কেবল সময়ের আগেই জানা কীগুলি নিষ্কাশন করতে পারে।
metakungfu

46

সবচেয়ে সহজ উপায় হ'ল 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"}

আমি বিশ্বাস করি যে বাগগুলি থাকতে পারে এমন অন্যান্য ক্রিয়াকলাপগুলি ঘোষণার পক্ষে এটি উপযুক্ত নয় এবং গত কয়েক বছর ধরে এমন একটি পদ্ধতি ব্যবহার করা ভাল যা টুইট করা হয়েছে।


এটির জন্য কমপক্ষে 2.5 তে অ্যাক্টিভেকর্ডের প্রয়োজন হয় না।
গ্রেওয়াল্ফ

13

সবচেয়ে সহজ উপায় হ'ল রতকে 'অ্যাক্টিভসপোর্ট' (বা রত্ন 'অ্যাক্টিভ_সপোর্ট') অন্তর্ভুক্ত করা।

params.slice(:choice1, :choice2, :choice3)


4
আপনার উত্তরে আরও বিশদ যুক্ত করুন।
মোহিত জৈন

13

যদি আপনি রেলগুলির সাথে কাজ করেন এবং আপনার কাছে একটি পৃথক তালিকার কী রয়েছে তবে আপনি *স্বরলিপিটি ব্যবহার করতে পারেন :

keys = [:foo, :bar]
hash1 = {foo: 1, bar:2, baz: 3}
hash2 = hash1.slice(*keys)
=> {foo: 1, bar:2}

অন্যান্য উত্তর হিসাবে বর্ণিত হয়েছে, আপনি slice!স্থানে হ্যাশ সংশোধন করতেও ব্যবহার করতে পারেন (এবং মোছা কী / মানগুলি ফিরিয়ে দিন)।


9

সম্পূর্ণ মূল প্রশ্নটি সমাধান করার জন্য এটি একটি লাইন:

params.select { |k,_| k[/choice/]}.values.join('\t')

তবে উপরের বেশিরভাগ সমাধানগুলি এমন একটি ক্ষেত্রে সমাধান করছে যেখানে আপনাকে আগে sliceবা কী কী সহজ রেজিপ্সপ ব্যবহার করা উচিত তা আগে সময়ের কীগুলি জানতে হবে ।

এখানে আরও একটি পদ্ধতি যা সহজ এবং আরও জটিল ব্যবহারের ক্ষেত্রে কাজ করে যা রানটাইম এ অদলবদলযোগ্য

data = {}
matcher = ->(key,value) { COMPLEX LOGIC HERE }
data.select(&matcher)

এখন এটি কেবল কীগুলি বা মানগুলি মিলে যাওয়ার জন্য আরও জটিল যুক্তিযুক্ত করার অনুমতি দেয় না, তবে এটি পরীক্ষা করা আরও সহজ এবং আপনি রানটাইমে ম্যাচিং লজিককে স্যুপ করতে পারেন।

মূল সমস্যাটি সমাধান করার জন্য প্রাক্তন:

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"

1
আমি ম্যাচারটি সত্যিই পছন্দ করি
কলিন


6

আপনি যদি বাকি হ্যাশ চান:

params.delete_if {|k, v| ! k.match(/choice[0-9]+/)}

বা যদি আপনি কেবল কীগুলি চান:

params.keys.delete_if {|k| ! k.match(/choice[0-9]+/)}

আপনি কতটি পছন্দ এক্স এবং অপ্রাসঙ্গিক এক্স নির্বাচন করেছেন বা ডিলেট_এটি বেছে নিতে পারেন তার উপর নির্ভর করে আরও ভাল হতে পারে। আপনার আরও পছন্দ থাকলে এক্স মুছে দিন_এফ ভাল।
আইকোস্টার

6

এটি একটি ইনিশিয়ালাইজারে রাখুন

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"}


4

বোনাস প্রশ্ন হিসাবে:

  1. যদি আপনার #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")
  2. যদি আপনার #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")

দুর্দান্ত সমাধান। একটি প্রশ্ন: ফিল্টার_প্রেমস.ম্যাপ (&: শেষ)) যদি তা হয় তবে 'শেষ' কী? আমি কি হ্যাশটির মান পেতে &: মান ব্যবহার করতে পারি?
ডেরেক

mapএটি যুক্তি হিসাবে ব্লক নেয় আপনি উড়তে ব্লক তৈরি করতে পারেন, নির্মাণের সাথে &:method, যা ব্লক তৈরি করবে {|v| v.method }। আমার ক্ষেত্রে &:lastঅ্যারে (2-উপাদান অ্যারে) যুক্তিতে ডাকা হয়েছিল। আপনি যদি এটির সাথে খেলতে চান তবে প্রথমে পরীক্ষা করুন যে আপনি কোন যুক্তিতে অবরুদ্ধ হয়ে যাচ্ছেন (1 টি যুক্তি পান, এটি একাধিক যুক্তিতে বিভক্ত করবেন না!) এবং 1 টি পদ্ধতি (যার সাহায্যে আপনি চেইন পদ্ধতিতে পারেন না &:method) যা আপনাকে ফিরিয়ে দেবে তা খুঁজে পাওয়ার চেষ্টা করুন চাই। যদি এটি সম্ভব হয়, তবে আপনি শর্টকাট ব্যবহার করতে পারেন, যদি না হয় তবে আপনার সম্পূর্ণ ব্লক দরকার
এমবিও

2
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"}

0

আমার অনুরূপ সমস্যা ছিল, আমার ক্ষেত্রে সমাধানটি ছিল একটি লাইনার যা কীগুলি প্রতীক না হলেও এমনকি কাজ করে তবে আপনার অ্যারেতে মানদণ্ড কীগুলি থাকা দরকার need

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"}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.