কীভাবে কী কী এবং মানগুলিকে একটি হ্যাশে অদলবদল করতে হয়


154

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

আমি নিম্নলিখিত হ্যাশ আছে:

{:a=>:one, :b=>:two, :c=>:three}

যা আমি রূপান্তর করতে চাই:

{:one=>:a, :two=>:b, :three=>:c}

ব্যবহার করা mapবরং ক্লান্তিকর বলে মনে হচ্ছে। এর কি আরও ছোট সমাধান আছে?

উত্তর:


280

রুবির কাছে হ্যাশের জন্য একটি সহায়ক পদ্ধতি রয়েছে যা আপনাকে একটি হ্যাশকে উল্টানো যেমন আচরণ করতে দেয় (মূলত, আপনাকে মূল্যগুলির মাধ্যমে কীগুলি অ্যাক্সেস করে):

{a: 1, b: 2, c: 3}.key(1)
=> :a

যদি আপনি ইনভার্টেড হ্যাশ রাখতে চান, তবে হ্যাশ # বিপরীতে বেশিরভাগ পরিস্থিতিতে কাজ করা উচিত:

{a: 1, b: 2, c: 3}.invert
=> {1=>:a, 2=>:b, 3=>:c}

কিন্তু ...

যদি আপনার সদৃশ মান থাকে invertতবে আপনার মানগুলির সর্বশেষ ঘটনাটি বাদ দিলে সমস্ত বাতিল হয়ে যাবে (কারণ এটি পুনরুক্তির সময় সেই কীটির জন্য নতুন মান প্রতিস্থাপন করতে থাকবে)। তেমনি, keyকেবল প্রথম ম্যাচটি ফিরবে:

{a: 1, b: 2, c: 2}.key(2)
=> :b

{a: 1, b: 2, c: 2}.invert
=> {1=>:a, 2=>:c}

সুতরাং, যদি আপনার মানগুলি অনন্য হয় তবে আপনি ব্যবহার করতে পারেন Hash#invert। যদি তা না হয় তবে আপনি সমস্ত মানকে এটির মতো রাখতে পারেন:

class Hash
  # like invert but not lossy
  # {"one"=>1,"two"=>2, "1"=>1, "2"=>2}.inverse => {1=>["one", "1"], 2=>["two", "2"]} 
  def safe_invert
    each_with_object({}) do |(key,value),out| 
      out[value] ||= []
      out[value] << key
    end
  end
end

দ্রষ্টব্য: পরীক্ষাগুলি সহ এই কোডটি এখন গিটহাবে রয়েছে

বা:

class Hash
  def safe_invert
    self.each_with_object({}){|(k,v),o|(o[v]||=[])<<k}
  end
end

4
each_with_objectএখানে চেয়ে বেশি বোধগম্য করে তোলে inject
অ্যান্ড্রু মার্শাল

যাতে এটি হয়ে যায় each_with_object({}){ |i,o|k,v = *i; o[v] ||=[]; o[v] << k}... সুন্দর
নাইজেল থর্ন

3
ঈশ্বর. আমি জানি না আপনি কি করতে পারেন | (কী, মান), আউট | এতো দুর্দান্ত, আমি কী এবং মানের পরিবর্তে সেই অ্যারেটি সেখানে আগত বলে ঘৃণা করি। অনেক অনেক ধন্যবাদ
আইউরি জি

63

আপনি বাজি ধরুন তো একটা আছে! রুবিতে জিনিসগুলি করার জন্য সর্বদা একটি ছোট উপায় আছে!

এটি বেশ সহজ, কেবল ব্যবহার করুন Hash#invert:

{a: :one, b: :two, c: :three}.invert
=> {:one=>:a, :two=>:b, :three=>:c}

এট ভয়েইল!


4
হ্যাশ # বিপরীত কাজ করে না যদি আপনার হ্যাশে একই মানগুলি একাধিকবার প্রদর্শিত হয়।
টিলো

2
files = {
  'Input.txt' => 'Randy',
  'Code.py' => 'Stan',
  'Output.txt' => 'Randy'
}

h = Hash.new{|h,k| h[k] = []} # Create hash that defaults unknown keys to empty an empty list
files.map {|k,v| h[v]<< k} #append each key to the list at a known value
puts h

এটি সদৃশ মানগুলিও পরিচালনা করবে।


1
আপনি প্রতিটি পদক্ষেপে কী ঘটছে তার উত্তরটি কিছুটা ব্যাখ্যা করতে পারেন?
সাজ্জাদ মুর্তজা

ব্যক্তিগতভাবে আমি হ্যাশের ডিফল্ট মান আচরণ সেট করা এড়াতে চাই। আমি উদ্বেগ প্রকাশ করছি যে আমি এই হ্যাশটিকে যা কিছু কোড দিই তা কোনও হ্যাশকে সেভাবে আচরণ করার প্রত্যাশা করে না এবং এটি পরে কিছু জঘন্য ত্রুটির কারণ হতে পারে। আমি সত্যিই এই উদ্বেগকে ন্যায়সঙ্গত করতে পারি না। এটি কেবল একটি সন্দেহ যা আমি উপেক্ষা করতে পারি না বলে মনে হয়। নূন্যতম আশ্চর্য কি?
নাইজেল থর্ন

কোড সহ উত্তর দেওয়ার সময় কোডটি কীভাবে কাজ করে এবং কেন এটি উপযুক্ত সমাধান তা ব্যাখ্যা করা সত্যিই গুরুত্বপূর্ণ। লক্ষ্যটি কেবল তাত্ক্ষণিক সমস্যার সমাধান নয়, শিক্ষিত করা।
টিন ম্যান

1
# this doesn't looks quite as elegant as the other solutions here,
# but if you call inverse twice, it will preserve the elements of the original hash

# true inversion of Ruby Hash / preserves all elements in original hash
# e.g. hash.inverse.inverse ~ h

class Hash

  def inverse
    i = Hash.new
    self.each_pair{ |k,v|
      if (v.class == Array)
        v.each{ |x|
          i[x] = i.has_key?(x) ? [k,i[x]].flatten : k
        }
      else
        i[v] = i.has_key?(v) ? [k,i[v]].flatten : k
      end
    }
    return i
  end

end

Hash#inverse আপনি দেয়:

 h = {a: 1, b: 2, c: 2}
 h.inverse
  => {1=>:a, 2=>[:c, :b]}
 h.inverse.inverse
  => {:a=>1, :c=>2, :b=>2}  # order might not be preserved
 h.inverse.inverse == h
  => true                   # true-ish because order might change

যদিও অন্তর্নির্মিত invertপদ্ধতিটি কেবল নষ্ট হয়েছে:

 h.invert
  => {1=>:a, 2=>:c}    # FAIL
 h.invert.invert == h 
  => false             # FAIL

1

অ্যারে ব্যবহার করা

input = {:key1=>"value1", :key2=>"value2", :key3=>"value3", :key4=>"value4", :key5=>"value5"}
output = Hash[input.to_a.map{|m| m.reverse}]

হ্যাশ ব্যবহার করা হচ্ছে

input = {:key1=>"value1", :key2=>"value2", :key3=>"value3", :key4=>"value4", :key5=>"value5"}
output = input.invert

1

আপনার যদি একটি হ্যাশ থাকে যেখানে কীগুলি অনন্য, আপনি হ্যাশ # বিপরীত ব্যবহার করতে পারেন :

> {a: 1, b: 2, c: 3}.invert
=> {1=>:a, 2=>:b, 3=>:c} 

আপনার অদ্বিতীয় কী না থাকলে এটি কাজ করবে না, তবে, যেখানে কেবলমাত্র শেষ দেখানো চাবিগুলি রাখা হবে:

> {a: 1, b: 2, c: 3, d: 3, e: 2, f: 1}.invert
=> {1=>:f, 2=>:e, 3=>:d}

আপনার যদি অনন্য অনন্য কীগুলির সাথে একটি হ্যাশ থাকে তবে আপনি এটি করতে পারেন:

> hash={a: 1, b: 2, c: 3, d: 3, e: 2, f: 1}
> hash.each_with_object(Hash.new { |h,k| h[k]=[] }) {|(k,v), h| 
            h[v] << k
            }     
=> {1=>[:a, :f], 2=>[:b, :e], 3=>[:c, :d]}

যদি হ্যাশের মানগুলি ইতিমধ্যে অ্যারে হয় তবে আপনি এটি করতে পারেন:

> hash={ "A" => [14, 15, 16], "B" => [17, 15], "C" => [35, 15] }
> hash.each_with_object(Hash.new { |h,k| h[k]=[] }) {|(k,v), h| 
            v.map {|t| h[t] << k}
            }   
=> {14=>["A"], 15=>["A", "B", "C"], 16=>["A"], 17=>["B"], 35=>["C"]}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.