I want avoid iterating over a nil array.
My bad solution:
if nil!=myArr
myArr.each { |item|
p item;
}
end
For a simple one-liner, you might also use unless myArr.nil?
myArr.each { |item| p item } unless myArr.nil?
Updating for Ruby >= 2.3.0:
If you are comfortable with a nil return rather than avoiding execution entirely, you can use the Safe navigation operator &.. Note though that this differs slightly. Whereas the unless version will skip execution entirely, the &. will execute but return nil.
myArr&.each { |item| p item }
# returns nil
In ruby, only nil and false are considered as false.
if myArr
myArr.each { |item|
p item
}
end
You can wrap the array value in Array().
Array(myArr).each { |item| p item }
As per the documentation, does this:
An array can also be created by using the Array() method, provided by Kernel, which tries to call to_ary, then to_a on its argument.
Basically, this will convert a nil value to []. Which would neither iterate, or throw an error. Fair warning, it will do the same to any value. Array("string") will create ["string"].
Alternatively, using andand
myArr.andand.each { | item| p item }
Simply checking for nil isn't always sufficient. Sometimes a variable you expect to be an array can be initialized as a non-array object when there is only one. It's not common, but proprietary services I've seen might give you a result of nil, "Name1", or ["Name1", "Name2", ...]. To reliably handle this range of input, I prefer to access my arrays like this:
Array.wrap(myArr).each { |item|
p item
}
Array.wrap will convert nil to [], Object to [Object], and leave existing arrays alone. Also handy for not silently butchering your hashes if one gets passed in instead of an array. (Calling Array(myArr) will convert myArr into an array, which destroys hashes rather than wrapping them in arrays.
myArr ||= []
and then iterate.
This will assign empty array to myArr only if it's nil.
Related
array = ["car","carrs"]
array.each { |x|
x.capitalize
}
I have tried doing with do too by removing the curly braces and adding do after .each, I have also tried for each in array, but that didnt work too. Am i doing something wrong because nothing gets capitalized?
String#capitalize returns a copy of the object with the first letter capitalized. What you're basically doing is looping through your array and generating new copies of the strings, but then immediately throwing them away.
You have a couple of ways to approach this:
You can use #map rather than #each to take each result of your loop block body and collect it into a new array:
array = ["car","carrs"]
capitalized_array = array.map { |x| x.capitalize }
Or, if you actually want to mutate the original strings, use String#capitalize! rather than capitalize, which mutates the input object, rather than returning a new object:
array = ["car","carrs"]
array.each { |x| x.capitalize! }
While it may seem tempting to use the mutative version, it is frequently a good idea to use non-mutative methods to produce transformations of your data, so you don't lose your original input data. Mutate-in-place can introduce subtle bugs by making the state of the data harder to reason about.
You have to understand the difference between map vs each. You can read it here.
For those who don't want to read that:
Each is like a more primitive version of map. It gives you every element so you can work with it, but it doesn’t collect the results. Each always returns the original, unchanged object. While map does the same thing, but. It returns a new array with the transformed elements.
So, you have to use map in order to return a new array:
array = ["car","carrs"]
capitalized_array = array.map { |x| x.capitalize }
# or
array = ["car","carrs"]
array.map! { |x| x.capitalize }
Now, what is the different between map and map!? We need to read the documentation
map invokes the given block once for each element of self. Creates a new array containing the values returned by the block. While map! invokes the given block once for each element of self, replacing the element with the value returned by the block.
The Enumerable#find method works by evaluating until the it finds an element which matches the condition in the block. Is there something similar for returning the first time that the block is not evaluated to nil? imagining one would have a collection of hashes:
value = nil
options.each do |o|
break if value = o[:desired]
end
value ||= DEFAULT
isn't there a method which already accomplishes this?
No point in making a lot of transformations to the collection, i'd like to minimize the number of allocations, so any solution which allocates a new Array will not be good for me.
find method will work for finding first element which has :desired key with minimum iterations.
I think you wish to get the value of desired key from the block instead of element itself - there is no method in Enumerable that behaves like a mixture of find and map - you will have to use the outer variable to which value is assigned inside the block as shown below.
options = [{foo: 1}, {desired: 2}, {bar: 3}]
value = nil
options.find do |o|
value = o[:desired]
break if value
end
p value
#=> 2
It more or less looks like your code, which should also work just fine.
Below is one way which you can use if you want to use Enumerable methods, but it will iterate over all elements.
p value = options.map { |o| value = o[:desired] }.compact.first
You can use reduce:
value = options.reduce(nil){|memo, entry| memo || entry[:desired] } || DEFAULT
As of Ruby 2.0, this can be accomplished by combining #map and #find with lazy enumerables:
value = options.lazy.map { |o| o[:desired] }.find { |x| !x.nil? } # or find(&:present?) with ActiveSupport
value ||= DEFAULT
This came up for me today: I think we can use break with a value from reduce
treasure = [1,2,3].reduce(nil) do |memo, value|
break memo if memo
foo(value)
end
How about
options.reduce{ |_,o|
break o if o[:desired]
DEFAULT
}
or
catch do |tag|
options.each{ |_,o| o[:desired] and throw tag, o }
DEFAULT
end
The latter allows for recursion.
My code is supposed to print integers in an array.
odds_n_ends = [:weezard, 42, "Trady Blix", 3, true, 19, 12.345]
ints = odds_n_ends.select { |x| if x.is_a?(Integer) then return x end }
puts ints
It gives me an error in the 2nd line - in 'block in <main>': unexpected return (LocalJumpError)
When I remove the return, the code works exactly as desired.
To find the mistake in my understanding of blocks, I read related posts post1 and post2. But, I am not able to figure out how exactly are methods and blocks being called and why my approach is incorrect.
Is there some call stack diagram explanation for this ? Any simple explanation ?
I am confused because I have only programmed in Java before.
You generally don't need to worry exactly what blocks are to use them.
In this situation, return will return from the outside scope, e.g. if these lines were in a method, then from that method. It's the same as if you put a return statement inside a loop in Java.
Additional tips:
select is used to create a copied array where only the elements satisfying the condition inside the block are selected:
only_ints = odds_n_ends.select { |x| x.is_a?(Integer) }
You're using it as a loop to "pass back" variables that are integers, in which case you'd do:
only_ints = []
odds_n_ends.each { |x| if x.is_a?(Integer) then only_ints << x end }
If you try to wrap your code in a method then it won't give you an error:
def some_method
odds_n_ends = [:weezard, 42, "Trady Blix", 3, true, 19, 12.345]
ints = odds_n_ends.select { |x| if x.is_a?(Integer) then return true end }
puts ints
end
puts some_method
This code output is true. But wait, where's puts ints??? Ruby didn't reach that. When you put return inside a Proc, then you're returning in the scope of the entire method. In your example, you didn't have any method in which you put your code, so after it encountered 'return', it didn't know where to 'jump to', where to continue to.
Array#select basically works this way: For each element of the array (represented with |x| in your code), it evaluates the block you've just put in and if the block evaluates to true, then that element will be included in the new array. Try removing 'return' from the second line and your code will work:
ints = odds_n_ends.select { |x| if x.is_a?(Integer) then true end }
However, this isn't the most Ruby-ish way, you don't have to tell Ruby to explicitly return true. Blocks (the code between the {} ) are just like methods, with the last expression being the return value of the method. So this will work just as well:
ints = odds_n_ends.select { |x| if x.is_a?(Integer) } # imagine the code between {} is
#a method, just without name like 'def is_a_integer?' with the value of the last expression
#being returned.
Btw, there's a more elegant way to solve your problem:
odds_n_ends = [:weezard, 42, "Trady Blix", 3, true, 19, 12.345]
ints = odds_n_ends.grep(Integer)
puts ints
See this link. It basically states:
Returns an array of every element in enum for which Pattern ===
element.
To understand Pattern === element, simply imagine that Pattern is a set (let's say a set of Integers). Element might or might not be an element of that set (an integer). How to find out? Use ===. If you type in Ruby:
puts Integer === 34
it will evalute to true. If you put:
puts Integer === 'hey'
it will evalute to false.
Hope this helped!
In ruby a method always returns it's last statement, so in generall you do not need to return unless you want to return prematurely.
In your case you do not need to return anything, as select will create a new array with just the elements that return true for the given block. As ruby automatically returns it's last statement using
{ |x| x.is_a?(Integer) }
would be sufficient. (Additionally you would want to return true and not x if you think about "return what select expects", but as ruby treats not nil as true it also works...)
Another thing that is important is to understand a key difference of procs (& blocks) and lambdas which is causing your problem:
Using return in a Proc will return the method the proc is used in.
Using return in a Lambdas will return it's value like a method.
Think of procs as code pieces you inject in a method and of lambdas as anonymous methods.
Good and easy to comprehend read: Understanding Ruby Blocks, Procs and Lambdas
When passing blocks to methods you should simply put the value you want to be returned as the last statement, which can also be in an if-else clause and ruby will use the last actually reached statement.
I am trying to write a function which returns the value of a hash key, when provided with an array of keys (and 'nil' if the key doesn't exist).
Consider the hash:
my_hash = {
font_size: 10,
font_family: "Arial",
boo: {
name: 'blah'
}
}
A stub of the method might be:
def get_value(hash, array_of_keys)
...
end
The reason being that I can access different keys in the hash which may not actually exist. So for example, I want 'blah', normally I would call my_hash[:boo][:name] however it may not already exist or it may be very deep. What I would like to do is have my function, which I could call with get_value(my_hash, [:boo, :name]) so that I can test that each key exists (so I don't get exceptions if any of them do not exist, and where it doesn't matter how 'deep' the value might be).
In my case, its not feasible to check the existence of each value I require (I might need to test existence of 10 consecutive keys) I simply need a function that I can say which value I need and get the value if it exists, and nil if it doesn't (so an exception isn't thrown trying to retrieve it).
I gave it a shot, trying to use a recursive function that 'pop's the first element in the array each time it loops but i couldn't workout how to return my value.
def get_value(val, arr)
if arr.count > 1
arr.each do |a|
get_value val[a], arr.pop
end
else
val[a]
end
end
get_value s, [:boo, :name]
This is my attempt (which doesn't work obviously) - can anyone help me solve this problem, or have an alternate solution that might be more elegant? A couple of points:
The keys are not guaranteed to exist, and I'd like to return nil in
those cases, and
The hash could potentially be very deep so it needs to handle any hash and any number of keys in the array (which is why I thought recursion might be the answer, but now I'm not so sure).
[:font_size].inject(my_hash){|h, k| h.to_h[k]} #=> 10
[:boo, :name].inject(my_hash){|h, k| h.to_h[k]} #=> "blah"
[:boo, :foo].inject(my_hash){|h, k| h.to_h[k]} #=> nil
class Hash
def get_value(array_of_keys)
return nil unless array_of_keys.is_a? Array
return nil if array_of_keys.empty?
return nil unless self.has_key? array_of_keys.first
if self[array_of_keys.first].is_a? Hash
self[array_of_keys.first].get_value(array_of_keys[1..-1])
else
self[array_of_keys.first]
end
end
end
my_hash = {
font_size: 10,
font_family: "Arial",
boo: {
name: 'blah'
} ,
radley: {
one: {
more: {
time: 'now'
}
}
}
}
p my_hash.get_value [:boo, :name]
p my_hash.get_value [:radley, :one, :more, :time]
p my_hash.get_value [:radley, :one, :other, :time]
Explanation
I'm adding the method directly to the Hash class so that you can call it as an instance method on existing hashes (makes for a nicer usage).
The method takes your array, returns nil if the argument is not actually an array, if the array is empty, of if the Hash doesn't contain a key matching the first element of the array.
Next, check to see if the value of that key is itself a Hash.
If so, call this very method on that Hash, with the rest of the array!
If the value is anything but a hash, return that value.
My stab at it, using recursion:
def get_value(hash, keys_array)
key = keys_array.shift
if hash.has_key? key
if hash[key].is_a?(Hash) && keys_array.size >= 1
get_value(hash[key], keys_array)
else
hash[key]
end
else
nil
end
end
I remove the first key from the keys_array
I check if that key exists in the Hash
If yes I check if the value for that key is a Hash and that we still have keys left in the array, if that's the case I call the method with that value and the array of keys left
If it's not a Hash, I just return the value
If the key does not exist, return nil
Nice problem by the way :)
Can someone help me understand the code below? I have been trying to add 'puts' to see what it does but keep getting errors. This is a code from an exercise/example I was supposed to already know, yet I have no idea what it is doing. It seems to me that I should have an items array defined before the method for this to make sense, but even then I wasn't able to make sense of it.
# search for `target_item` in `items`; return the array index
# where it first occurs
def find_item(items, target_item)
i = 0
while i < items.count
current_item = items[i]
if current_item == target_item
# found item; return its index; stop here and exit the
# method
return i
end
i += 1
end
# return nil to mean item not found
nil
end
You are correct about needing an array items to run your code. You will also need a value for the variable target_item. These two variables are passed as arguments to the method find_item. If the method finds the value of target_item in the array items it will return the index of that item in the array (0 for the first element, 1 for the second, and so on.); if it does not, it will return nil.
If you run your code in IRB, it will return => :find_item. That means it found no errors. That does not mean there are no errors, however, as error can surface when the code is run.
Let's try it with some data. After running the code defining the method (in IRB), run these three lines:
items = ['dog', 'cat', 'pig']
target_item = 'cat'
find_item(items, target_item) #=> 1
where #=> 1 means that the method returned 1, meaning that it found target_items at offset 1 in items, which is what we would expect.
This is equivalent to:
find_item(['dog', 'cat', 'pig'], 'cat')
On the other hand,
find_item(items, 'bird') #=> nil
as the array does not contain 'bird'. The two lines
current_item = items[i]
if current_item == target_item
can be combined into one:
if items[i] == target_item
but that's beside the point, because Rubiests would not write the method this way. Instead, you would commonly do it like this:
def find_item(items, target_item)
items.each_with_index { |e,i| return i if e == target_item }
nil
end
[Edit: #Mark has correctly pointed out a much simpler way of writing the method. I will stick with this version, however, as I think you will learn something useful by seeing how it works.]
The built-in Ruby method each_with_index is from the Enumgerable module, which is always available to you (along with 60+ other method defined in that module). When you reference a method, it's best to include the class or module in which it was defined. This method is Enumerable#each_with_index. Among other things, its easier to find documentation for the method if you know the class or module its from.
Although each_with_index was defined in the Enumerable module, it is an "enumerator", meaning that it feeds the values from items to the following block, denoted by {...} (as here) or do ... end.
Run this in IRB:
items = ['dog', 'cat', 'pig']
target_item = 'cat'
enum = items.each_with_index
#=> #<Enumerator: ["dog", "cat", "pig"]:each_with_index>
You can convert this to an array to see what it will feed the block:
enum.to_a
#=> [["dog", 0], ["cat", 1], ["pig", 2]]
Consider now the first element the enumerator will be passed to the block:
["dog", 0]
The block variables, e and i in
items.each_with_index { |e,i| return i if e == target_item }
will therefore be set equal to:
e => "dog"
i => 0
Therefore, e == target_item becomes "dog" == "cat", which is false, so return 0 is not executed. For the next items, however,
e => "cat"
i => 1
As "cat" == "cat" is true, return 1 is executed, and we are finished. If items did not contain cat, the enumerator would enumerate all items and control would go to the following statement, nil. As that is the last statement executed, the method would return nil.
This code appears to be a poorly rewritten Array#index. This is identical:
items.index(target_item)