ruby hash add key/value if modifier - ruby

I am working with a ruby hash that contains key/value pairs for creating a new subscriber in my MailChimp API.
user_information = {
'fname' => 'hello world',
'mmerge1' => 'Product X' if user.product_name.present?
}
Obviously, I am getting a syntax error of syntax error, unexpected modifier_if... I am basically only wanting to add the mmerge1 based upon the conditional being true.

You can't use if that way, inside a hash-initialization block. You'll have to conditionally add the new key/value after initializing the hash:
user_information = {
'fname' => 'hello world',
}
user_information['mmerge1'] = 'Product X' if user.product_name.present?

user_information = {'fname' => 'hello world'}
user_information.merge!({'mmerge1' => 'Product X'}) if user.product_name.present?
#=> {"fname"=>"hello world", "mmerge1"=>"Product X"}

If mmerge1 is allowed to be nil or an empty string, you can use the ?: ternary operator inside the hash:
user_information = {
'fname' => 'hello world',
'mmerge1' => user.product_name.present? ? 'Product X' : ''
}

If you use a conditional expression on the key you get a reasonably readable syntax and, at most, need to remove only 1 element from the Hash.
product_name = false
extra_name = false
user_information = {
'fname' => 'hello world',
product_name ? :mmerge1 : nil => 'Product X',
extra_name ? :xmerge1 : nil => 'Extra X'
}
user_information.delete nil
p user_information

Related

Ruby: how can I retrieve a value in a hash knowing its (array) path?

I've got this hash
parentNode = {
"titles" => {
"primary" => "On Days Like These",
"secondary" => "Matt Monro",
"tertiary" => nil
},
"synopses" => nil,
"image_url" => "https://ichef.bbci.co.uk/images/ic/{recipe}/p01bqrb8.jpg",
"duration" => nil
}
and I know the 'path' of the value I want :
path = ['titles','secondary']
How can I retrieve the corresponding value, which is Matt Monro ?
This works
puts parentNode['titles']['secondary']
but what I want is to fetch that same data using the path variable defined above. But
puts parentNode[path]
puts parentNode.dig(path)
does not shows anything.
I'm new to ruby, why is this not working ?
Thanks
Hash.dig accepts variable number of arguments, to convert array into "variable arguments" you need to use * (splat operator)
parentNode.dig(*path)

Elegantly return value(s) matching criteria from an array of nested hashes - in one line

I have been searching for a solution to this issue for a couple of days now, and I'm hoping someone can help out. Given this data structure:
'foo' => {
'bar' => [
{
'baz' => {'faz' => '1.2.3'},
'name' => 'name1'
},
{
'baz' => {'faz' => '4.5.6'},
'name' => 'name2'
},
{
'baz' => {'faz' => '7.8.9'},
'name' => 'name3'
}
]
}
I need to find the value of 'faz' that begins with a '4.', without using each. I have to use the '4.' value as a key for a hash I will create while looping over 'bar' (which obviously I can't do if I don't yet know the value of '4.'), and I don't want to loop twice.
Ideally, there would be an elegant one-line solution to return the value '4.5.6' to me.
I found this article, but it doesn't address the full complexity of this data structure, and the only answer given for it is too verbose; the looping-twice solution is more readable. I'm using Ruby 2.3 on Rails 4 and don't have the ability to upgrade. Are there any Ruby gurus out there who can guide me?
You can use select to filter results.
data = {'foo' => {'bar' => [{'baz' => {'faz' => '1.2.3'}, 'name' => 'name1'}, {'baz' => {'faz' => '4.5.6'}, 'name' => 'name2'}, {'baz' => {'faz' => '7.8.9'}, 'name' => 'name3'}]}}
data.dig('foo', 'bar').select { |obj| obj.dig('baz', 'faz').slice(0) == '4' }
#=> [{"baz"=>{"faz"=>"4.5.6"}, "name"=>"name2"}]
# or if you prefer the square bracket style
data['foo']['bar'].select { |obj| obj['baz']['faz'][0] == '4' }
The answer assumes that every element inside the bar array has the nested attributes baz -> faz.
If you only expect one result you can use find instead.

Ruby, iterating over a multi-value Hash using if/else, trying to return key/value pairs, fails when value is not found

I am trying to scan a string of raw input from a user and return a sentence that's composed of an array of arrays with the (TOKEN, WORD) pairings. If a word isn't part of the lexicon, then it should still return the WORD but set the TOKEN to an error token.
Inside the method "##dictionary.each do |type, list|" the initial if statement works fine at building a key/value array of found words, as long as the else statement is set to return nil. However, when I try and place error/words pairs into the array for the words not contained in the ##dictionary hash (i.e. those that fall into the else part of the code), I receive 5 separate pairs in the array for each word that the user entered, one for each iteration over each key for each word entered.
Does anybody have an idea how to return just one error/value pair to the array, instead of one for each of the five iterations for every word?
class Lexicon
##dictionary = {
'direction' => ['north', 'south', 'east', 'west', 'down', 'up', 'left', 'right', 'back'],
'verbs' => ['go', 'stop', 'kill', 'eat'],
'stop words' => ['the', 'in', 'of', 'on', 'at', 'it'],
'nouns' => ['door', 'bear', 'princess', 'cabinet'],
'numbers' => [0..9]
}
stuff = $stdin.gets.chomp
##words = stuff.split(' ')
def self.scan
result = []
##words.each do |text_element|
categorized = []
##dictionary.each do |type, list|
if
list.include?(text_element.downcase)
categorized = [type, text_element]
result.push(categorized)
else
nil
#categorized = ["ERROR", text_element]
#result.push(categorized)
end
end
end
print result
end
Lexicon.scan
end
It happens because of each iterates over all elements and it is true once or never.
This reduction of your code should help you understand what happen:
dictionary = {
'direction' => ['north', 'south'],
'verbs' => ['go', 'stop', 'kill', 'eat'],
'whathever' => ['blah']
}
text = 'go'
dictionary.each do |type, list|
if p list.include?(text) # added p
then
p text
else
p 'error'
end
end
It returns:
# false
# "error"
# true
# "go"
# false
# "error"
You need a different approach, for example:
text = 'nothing'
result = dictionary.find { |_, v| v.include? text }
result ? [result.keys, text] : "Error"
While it may feel organize to have the dictionary categorized by lists, this would be both simplified and much faster were the dictionary to be flattened and have a default set to the 'ERROR' token.
For example:
##dictionary = {
'direction' => ['north', 'south', 'east', 'west', 'down', 'up', 'left', 'right', 'back'],
'verbs' => ['go', 'stop', 'kill', 'eat'],
...
Becomes this:
##dictionary = {
'north' => 'direction',
'south' => 'direction',
...
'go' => 'verbs',
'stop' => 'verbs',
...
}
##dictionary.default = 'ERROR'
This way, your lookup becomes linear and without unnecessary boolean logic, like so.
def scan
result = stuff.split(' ').map do |word|
[##dictionary[word.downcase], word]
end
print result
end
This has worked for me. Thanks to Sebastian Scholl for the idea of simplifying the dictionary.
class Lexicon
##dictionary = {
'direction' => ['north', 'south', 'east', 'west', 'down', 'up', 'left', 'right', 'back'],
'verbs' => ['go', 'stop', 'kill', 'eat'],
'stop words' => ['the', 'in', 'of', 'on', 'at', 'it'],
'nouns' => ['door', 'bear', 'princess', 'cabinet'],
'numbers' => [0..9]
}
stuff = $stdin.gets.chomp
##words = stuff.downcase.split(' ')
def self.scan
result = []
values = []
##dictionary.each do |key, value|
values << value
end
value_list = values.flatten.uniq
##words.each do |text_element|
if value_list.include?(text_element)
##dictionary.each do |key, value|
if value.include?(text_element)
categorized = [key, text_element]
result.push(categorized)
else
nil
end
end
else
result.push(["Error, #{text_element}"])
end
end
print result
end
Lexicon.scan
end

Get key from inner Hash

I want to get the value from the inner hash. In this case RU - alway the first value.
PAYMENT_TYPE_TO_CURRENCY_AND_COUNTRY_MAPPING = {
zimpler: { 'EUR' => ['FI'], 'SEK' => ['SE'] },
qiwi: { 'EUR' => ['RU', 'KZ'], 'RUB' => ['RU'], 'KZT' => ['KZ'], 'USD' => ['UA'] },
payu: { 'CZK' => ['CZ'], 'PLN' => ['PL']},
entercash: { 'EUR' => ['AT', 'DE', 'FI'], 'SEK' => ['SE'] },
carulla: { 'USD' => ['CO'] }
}
I tried this:
PAYMENT_TYPE_TO_CURRENCY_AND_COUNTRY_MAPPING.each do |payment_method_key, array|
p payment_method_key.to_s /// prints "qiwi" - OK
p array.keys.first /// prints "EUR" - OK
p array[array.keys.first] //// prints ["RU", "KZ"] - not OK - need only RU
end
How I can implement this functionality?
It isn't clear to me if you only want to get the first element each time (which the previous answer accomplishes), or if you only want a 'specific' element each time. Another way to do this that allows you to select specific countries no matter where they are in the array would be:
PAYMENT_TYPE_TO_CURRENCY_AND_COUNTRY_MAPPING.each_pair do |method, currencies|
currencies.each_pair do |currency, countries|
countries.each do |country|
p country if country == "RU"
end
end
end
output:
=> "RU"
"RU"
return value would be the original hash:
=> {:zimpler=>{"EUR"=>["FI"], "SEK"=>["SE"]},
:qiwi=>{"EUR"=>["RU", "KZ"], "RUB"=>["RU"], "KZT"=>["KZ"], "USD"=>["UA"]},
:payu=>{"CZK"=>["CZ"], "PLN"=>["PL"]},
:entercash=>{"EUR"=>["AT", "DE", "FI"], "SEK"=>["SE"]},
:carulla=>{"USD"=>["CO"]}}

what is difference between -> and => in laravel

This is the code where we have used -> and => .
But I always get confused, while writing code at that time which one to use and where.
So seeking its logic to easily remember it.
$quan= $request->all();
ChaiExl::create(['date'=>date('Y-m-d',strtotime($quan['dt'])),'quantity'=>$quan['quan']]);
return view('edit',['row'=>$row]);
-> and => are both operators.
The difference is that => is the assign operator that is used while creating an array.
For example:
array(key => value, key2 => value2)
And
-> is the access operator. It accesses an object's value
This is PHP syntax, not laravel specifics.
=> is for setting values in arrays:
$foobar = array(
'bar' => 'something',
'foo' => 222
);
or
$foobar = [
'bar' => 'something',
'foo' => 222
];
-> is used for calling class methods and properties:
class MyClass {
public $bar = 'something';
public function foo() {
}
}
$foobar = new MyClass();
$foobar->foo();
echo $foobar->bar;
=> is used in associative array key value assignment. look below:
array(
key => value,
key2 => value2,
key3 => value3,
...
)
-> is used to access an object method or property. Example:
$object->method() or $object->var1
When you want to access a method from a class you will use -> that is
$class = new Class;
$class->mymethod();
but when you want to declare an array of object pairs you use => that is
$property = ('firstproperty', ['second'=>'secondPair','third'=>'thirdPair'])

Resources