Find first hash key with nil value - ruby-on-rails

def job_ids
{
job_id: r.job_id,
job_2_id: r.job_2_id,
job_3_id: r.job_3_id
}
end
def available_job_id
job_ids.find { |_k, v| v.nil? }[0].to_s
end
im checking which key has the first value of nil,and then i convert it to string.
what's the best way to do it?
This seems to be dirty?
job_ids.find { |_k, v| v.nil? }[0].to_s
UPDATE:
here's the desired output so far...
[79] pry(main)> job_ids.find{|k, v| v.nil?}[0].to_s
=> "job_2_id"

Try this
job_ids.key(nil).to_s

You can just use key
job_ids.key(nil).to_s
#=> "job_2_id"

Related

Rails deserialize format output

I face a problem, I don't know how to arrange the serialize format in rails.
I have models call MissionSet, QuestionSet, Group
The MissionSet will return like this
I want it to become like this, it's really a challenge to me, because I am not familiar with handling this format.
Here's something that will get you started:
x = {}
inp.each do |h|
h['assignments'].each do |k, _|
x[k] ||= []
x[k] << h['question_set_id']
end
end
out = x.map do |key, value|
{
group_id: key,
question_sets: value.map { |v| { id: v} }
}
end
puts out.inspect
This code will first group your questions by the ids in assignments and then format it as you wanted.

How to find out the key starting with same word?

I'm having the following hash:
hash = {
"Jason_1" => 2,
"Jason_2" => 3,
"Allison" => 1,
"Jason_3" => 1,
"Michelle" => 1
}
How can I obtain the values of the key starting with "Jason"? Can anyone help me?
Here are a one liners:
# returns a hash with the elements
hash.select { |e| e.start_with? 'Jason' }
# if you want only keys
hash.select { |e| e.start_with? 'Jason' }.keys
# if you want only values
hash.select { |e| e.start_with? 'Jason' }.values
Yet another way:
hash.map { |key, value| key =~ /\AJason/ && value }.compact
Another way with regexp:
hash.select { |x| x =~ /^Jason/ }.values
Another way using scan and find_all method:
Hash[hash.find_all { |key, val| not key.scan(/^Jason/).empty? }]
If you are working in rails this should also work fine:
hash.slice(*hash.keys.grep(/^Jason/))
You can do this in a efficient way and in a single line:
hash.select{|s,v| s =~ /^Jason_/}

How to sort Ruby Hash based on date?

I have a hash object with the following structure:
{"action1"=>
{"2014-08-20"=>0,
"2014-07-26"=>1,
"2014-07-31"=>1
},
"action2"=>
{"2014-08-01"=>2,
"2014-08-20"=>2,
"2014-07-25"=>2,
"2014-08-06"=>1,
"2014-08-21"=>1
}
"action3"=>
{"2014-07-30"=>2,
"2014-07-31"=>1,
"2014-07-22"=>1,
}
}
I want to sort the hash based on the date and return back a Hash(Not array). The final result should be:
{"action1"=>
{"2014-07-26"=>1,
"2014-07-31"=>1,
"2014-08-20"=>0
},
"action2"=>
{"2014-07-25"=>2,
"2014-08-01"=>2,
"2014-08-06"=>2,
"2014-08-20"=>1,
"2014-08-21"=>1
}
"action3"=>
{"2014-07-22"=>1,
"2014-07-30"=>2,
"2014-07-31"=>1
}
}
Iterate over the hash, and for each value, sort.
h = {"action1"=>
{"2014-08-20"=>0,
"2014-07-26"=>1,
"2014-07-31"=>1
},
"action2"=>
{"2014-08-01"=>2,
"2014-08-20"=>2,
"2014-07-25"=>2,
"2014-08-06"=>1,
"2014-08-21"=>1
},
"action3"=>
{"2014-07-30"=>2,
"2014-07-31"=>1,
"2014-07-22"=>1,
}
}
h.each do |k, v|
h[k] = Hash[v.sort]
end
Here you need to iterate your hash and fetch the value than you need to apply sort_by function on each value so you will get your result
hashName.each do |key, hash|
Hash[hashName.sort_by{|k,v| k}]
end
This is all you need:
h.each { |k,v| h[k] = v.sort.to_h }
#=> {"action1"=>{"2014-07-26"=>1, "2014-07-31"=>1, "2014-08-20"=>0},
# "action2"=>{"2014-07-25"=>2, "2014-08-01"=>2, "2014-08-06"=>1,
# "2014-08-20"=>2, "2014-08-21"=>1},
# "action3"=>{"2014-07-22"=>1, "2014-07-30"=>2, "2014-07-31"=>1}}
Hash#to_h appeared in Ruby 2.0. For earlier versions, use the class method Hash::[]: i.e., replace v.sort.to_h with Hash[v.sort].

ActiveRecord to_json to exclude null values

Is there an ActiveRecord setting that will allow me to remove null values before serializing ActiveRecord objects into json?
If not, what's the best way to do this?
Thanks
You can override serializable_hash method inside your model
def serializable_hash(options)
super(options).select { |_, v| v }
end
By the way, if you are going to use include (e.g. Project.all.as_json(include: :tasks)) then you need to override serializable_hash in both models.
UPDATE: Version 0.10+
def serializable_hash(adapter_options = nil, options = {}, adapter_instance = self.class.serialization_adapter_instance)
super(adapter_options, options, adapter_instance).select { |_, v| v }
end
Maybe
#instance.attributes.delete_if { |k, v| v.nil? }.to_json

How to recursively remove all keys with empty values from (YAML) hash?

I have been trying to get rid of all hash keys in my YAML file that have empty (blank) values or empty hashes as values.
This earlier post helped me to get it almost right, but the recursive one-liner leaves my YAML dump with empty hashes whenever there is sufficiently deep nesting.
I would really appreciate any help on this. Thanks!
proc = Proc.new { |k, v| (v.kind_of?(Hash) && !v.empty? ) ? (v.delete_if(&proc); nil) : v.blank? }
hash = {"x"=>{"m"=>{"n"=>{}}}, 'y' => 'content'}
hash.delete_if(&proc)
Actual output
{"x"=>{"m"=>{}}, "y"=>"content"}
Desired output
{"y"=>"content"}
class Hash
def delete_blank
delete_if{|k, v| v.empty? or v.instance_of?(Hash) && v.delete_blank.empty?}
end
end
p hash.delete_blank
# => {"y"=>"content"}
Here's a more generic method:
class Hash
def deep_reject(&blk)
self.dup.deep_reject!(&blk)
end
def deep_reject!(&blk)
self.each do |k, v|
v.deep_reject!(&blk) if v.is_a?(Hash)
self.delete(k) if blk.call(k, v)
end
end
end
{ a: 1, b: nil, c: { d: nil, e: '' } }.deep_reject! { |k, v| v.blank? }
==> { a: 1 }
I think this the most correct version:
h = {a: {b: {c: "",}, d:1}, e:2, f: {g: {h:''}}}
p = proc do |_, v|
v.delete_if(&p) if v.respond_to? :delete_if
v.nil? || v.respond_to?(:"empty?") && v.empty?
end
h.delete_if(&p)
#=> {:a=>{:d=>1}, :e=>2}
I know this thread is a bit old but I came up with a better solution which supports Multidimensional hashes. It uses delete_if? except its multidimensional and cleans out anything with a an empty value by default and if a block is passed it is passed down through it's children.
# Hash cleaner
class Hash
def clean!
self.delete_if do |key, val|
if block_given?
yield(key,val)
else
# Prepeare the tests
test1 = val.nil?
test2 = val === 0
test3 = val === false
test4 = val.empty? if val.respond_to?('empty?')
test5 = val.strip.empty? if val.is_a?(String) && val.respond_to?('empty?')
# Were any of the tests true
test1 || test2 || test3 || test4 || test5
end
end
self.each do |key, val|
if self[key].is_a?(Hash) && self[key].respond_to?('clean!')
if block_given?
self[key] = self[key].clean!(&Proc.new)
else
self[key] = self[key].clean!
end
end
end
return self
end
end
Just a bit related thing. If you want to delete specified keys from nested hash:
def find_and_destroy(*keys)
delete_if{ |k, v| (keys.include?(k.to_s) ? true : ( (v.each { |vv| vv = vv.find_and_destroy(*keys) }) if v.instance_of?(Array) ; (v.each { |vv| vv = vv.find_and_destroy(*keys) }) if v.instance_of?(Hash); false) )}
end
.You can also customize it further
hash = {"x"=>{"m"=>{"n"=>{}}}, 'y' => 'content'}
clean = proc{ |k,v| !v.empty? ? Hash === v ? v.delete_if(&clean) : false : true }
hash.delete_if(&clean)
#=> {"y"=>"content"}
or like #sawa suggested, you can use this proc
clean = proc{ |k,v| v.empty? or Hash === v && v.delete_if(&clean) }

Resources