I have this code below:
a = [435,276,434]
def product(a)
final = 1
for e in a
for p in a[e]
final*=p
end
end
final
end
puts product(a)
I'm wondering how I can iterate over this array twice where the result is 4*3*5 = 60, 2*7*6 = 85, and 4*3*4 = 48
I wrote some code up above which I thought would do the trick here but Ruby keeps on returning an error.
A few points to consider:
In Ruby you basically never use a for loop to iterate over things. #each is better. You get to pass a block to that, which gives you all kinds of room for flexibility and expressiveness.
Also, you can't - normally - iterate over an Integer. Remember that an Integer is a store of numerical value, not a particular representation, so it would have to be dependent on the base of the representation you wanted. If you want a string of characters, each of which happen to be numbers, well, guess what? You want a String, like seph's solution here. Or an Array, which would probably make even more sense because each integer would remain an integer and wouldn't have to be parsed back and forth.
Tell you what, let's build a really cool method to do this and staple this on to Integer, and hopefully demonstrate some of Ruby's cool features.
class Integer
include Enumerable
def each(base = 10, &blk)
front, back = abs.divmod(base)
if front > 0
front.each(base, &blk)
end
yield back
end
end
This little number takes a base and a block, gets the absolute value of the integer (since technically the minus isn't a digit), then uses divmod to split the number, chopping off the final digit. We store the pieces in front and back. We check to see if there are any more digits, indicated by front being 0, and if there is we recursively call this method, with that block. Then we just yield the back, sending the digit to the block.
Since we have now defined an each method, we are now free to include Enumerable which gets us a ton of stuff!
As long as that modification is active, your product method becomes:
(if you wanted to print 60 84 48): a.map {|n| n.reduce(:*)}
(or if you wanted to print 241920): a.reduce(:*).reduce(:*)
Pretty nice!
So, this total solution is quite a bit longer than seph's one-liner, and in truth if I needed to actually do something I would just to_s. Is my solution quicker to execute? Who knows? It's certainly more expressive, though, and that's why you're using Ruby in the first place.
If you want to solve a problem, yeah, absolutely, to_s. But if you want your code to express a philosophy you have about numbers, about how really they're just collections too - and they are, in a weird set theory kind of way, Ruby lets you empower them to be that. And this way that doesn't need Strings at all, they're totally free of their grudging assistance. And you can iterate through different bases, which is super useful if you're doing hex or binary, which preserves more of the numbery essence of them.
In this world that you and I have built together, Jamaal, little integers run wild through the forests with the big boys. And that's wonderful.
You could convert it to a string(.to_s). Then it's easy to get each digit as a char(.chars), convert them back to an integers(.map(&:to_i)) and multiply them together(.reduce(:*))
a = [435,276,434]
a.map {|n| n.to_s.chars.map(&:to_i).reduce(:*) }
=> [60, 84, 48]
Here's one way you could fix your code:
a = [435,276,434]
def product(a)
result = [] # Create an empty array that will become [60, 85, 48]
for e in a
final = 1
# Convert the integer e to a string (e.g., "435")
str = e.to_s
# Iterate over each char of the string (e.g., "4", "3" and "5")
str.each_char do |c|
# Convert the character 'c' to an integer (digit) then multiply final by that integer
final *= c.to_i
end
# Append the value of final to the result array
result << final # e.g., when result = [60], result << 85 => [60, 85]
end
result # => [60, 85, 48]
end
product(a) # => [60, 85, 48]
Now let's see how we can improve it. Firstly, we can chain operations and avoid the use of the temporary variable str. Also, you'll find that for loops, each is generally preferable to for (especially because you can use a block with each), so I'll change that too. While I'm at it, since the each_char loop contains only one statement, I'll write the block with brackets rather than do/end. We now have:
def product(a)
result = [] # Create an empty array that will become [60, 85, 48]
a.each do |e|
final = 1
e.to_s.each_char {|c| final *= c.to_i}
result << final
end
result
end
When I look at this, I'm thinking I want to convert each element of the array a to something else (the product of its digits). That suggests the use of the Array method map! (or its synonym, collect!), rather than each. Since a is the argument of the method product, if I use a.map!, that will change the values of a in the method that calls product. That may or may not be OK, but since I'm returning an array of the computed values, it's probably not OK, so I'll apply map! to a copy of a. (It's called a "shallow" copy, which is not important here, but can be in other situations.) We now have this:
def product(a)
result = a.dup
result.map! do |e|
final = 1
e.to_s.each_char {|c| final *= c.to_i}
final
end
result
end
We don't need the last result, because map! returns result (as well as changing result). Hey, that also means we can use just map (makes no difference). Also, we can chain a.dup and map to get rid of result:
def product(a)
a.dup.map do |e|
final = 1
e.to_s.each_char {|c| final *= c.to_i}
final
end
end
Man, we're cookin' with gas! Next, whenever you see a block that computes the product or sum of something, think inject (or its synomym, reduce):
def product(a)
a.dup.map do |e|
e.to_s.each_char.inject(1) {|final, c| final * c.to_i}
end
end
Suppose a < 0. What to do? (#Leon's answer twigged me to that possibility.) A negative receiver makes no sense to each, so let's raise an exception if that happens:
def product(a)
raise RuntimeError, "Receiver must be non-negative" if self < 0
a.dup.map do |e|
e.to_s.each_char.inject(1) {|final, c| final * c.to_i}
end
end
You may want to stop here, but you could replace map with another `inject:
def product(a)
raise RuntimeError, "Receiver must be non-negative" if self < 0
a.inject([]) {|result, e| result.concat.e.to_s.each_char.inject(1) {|final, c| final * c.to_i}}
end
Here the argument for inject is an empty array called result. Notice that, since we haven't changed a, we no longer needed dup. (I see #Kingston arrived at a similar answer.) If you prefer, you could write this as:
def product(a)
raise RuntimeError, "Receiver must be non-negative" if self < 0
a.inject([]) {|result, e| result << e.to_s.each_char.inject(1) {|final, c| final * c.to_i}; result}
end
but notice the need for that pesky ; result an the end.
You might think that the end result of all these "improvements" is too much of a mind-bender, or that the author is just showing off. That's what I thought when I was new to Ruby. With experience, however, you will find it is very natural and reads like a sentence. It also makes debugging easier: working left-to-right, you can test each link of the chain to make sure it's working.
a.collect{|x|
result = 1
x.to_s.split('').each{|y| result *= y.to_i}
result
}
If the intent is to just iterate over the digits, you can use the string slice methods too.
num = a[0].to_s # "435"
final = num[0,1].to_i * num[1,1].to_i * num[2,1].to_i #4*3*5
or
final = num[0..1].to_i * num[1..2].to_i * num[2..3].to_i
For the given question, if you know it is an array of 3 digits each, then you can skip the inner loop and the solution could be like this:
a = [435,276,434]
def product(a)
a.map! do |digits|
final = 1
num = digits.to_s
final = num[0,1].to_i * num[1,1].to_i * num[2,1].to_i
end
end
puts product(a).inspect
This answer is just for the said question. Since it manipulates the same array, it edits the receiver. For a more detailed and complete solution, check out Cary Swoveland's answer.
Related
I have been reading this:
https://docs.ruby-lang.org/en/2.4.0/Enumerator.html
I am trying to understand why someone would use .to_enum, I mean how is that different than just an array? I see :scan was passed into it, but what other arguments can you pass into it?
Why not just use .scan in the case below? Any advice on how to understand .to_enum better?
"Hello, world!".scan(/\w+/) #=> ["Hello", "world"]
"Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"]
"Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"]
Arrays are, necessarily, constructs that are in memory. An array with a a lot of entries takes up a lot of memory.
To put this in context, here's an example, finding all the "palindromic" numbers between 1 and 1,000,000:
# Create a large array of the numbers to search through
numbers = (1..1000000).to_a
# Filter to find palindromes
numbers.select do |i|
is = i.to_s
is == is.reverse
end
Even though there's only 1998 such numbers, the entire array of a million needs to be created, then sifted through, then kept around until garbage collected.
An enumerator doesn't necessarily take up any memory at all, not in a consequential way. This is way more efficient:
# Uses an enumerator instead
numbers = (1..1000000).to_enum
# Filtering code looks identical, but behaves differently
numbers.select do |i|
is = i.to_s
is == is.reverse
end
You can even take this a step further by making a custom Enumerator:
palindromes = Enumerator.new do |y|
1000000.times do |i|
is = (i + 1).to_s
y << i if (is == is.reverse)
end
end
This one doesn't even bother with filtering, it just emits only palindromic numbers.
Enumerators can also do other things like be infinite in length, whereas arrays are necessarily finite. An infinite enumerator can be useful when you want to filter and take the first N matching entries, like in this case:
# Open-ended range, new in Ruby 2.6. Don't call .to_a on this!
numbers = (1..).to_enum
numbers.lazy.select do |i|
is = i.to_s
is == is.reverse
end.take(1000).to_a
Using .lazy here means it does the select, then filters through take with each entry until the take method is happy. If you remove the lazy it will try and evaluate each stage of this to completion, which on an infinite enumerator never happens.
I'm doing a SaaS course with Ruby. On an exercise, I'm asked to calculate the cartesian product of two sequences by using iterators, blocks and yield.
I ended up with this, by pure guess-and-error, and it seems to work. But I'm not sure about how. I seem to understand the basic blocks and yield usage, but this? Not at all.
class CartProd
include Enumerable
def initialize(a,b)
#a = a
#b = b
end
def each
#a.each{|ae|
#b.each{|be|
yield [ae,be]
}
}
end
end
Some explanation for a noob like me, please?
(PS: I changed the required class name to CartProd so people doing the course can't find the response by googling it so easily)
Let's build this up step-by-step. We will simplify things a bit by taking it out of the class context.
For this example it is intuitive to think of an iterator as being a more-powerful replacement for a traditional for-loop.
So first here's a for-loop version:
seq1 = (0..2)
seq2 = (0..2)
for x in seq1
for y in seq2
p [x,y] # shorthand for puts [x, y].inspect
end
end
Now let's replace that with more Ruby-idiomatic iterator style, explicitly supplying blocks to be executed (i.e., the do...end blocks):
seq1.each do |x|
seq2.each do |y|
p [x,y]
end
end
So far, so good, you've printed out your cartesian product. Now your assignment asks you to use yield as well. The point of yield is to "yield execution", i.e., pass control to another block of code temporarily (optionally passing one or more arguments).
So, although it's not really necessary for this toy example, instead of directly printing the value like above, you can yield the value, and let the caller supply a block that accepts that value and prints it instead.
That could look like this:
def prod(seq1, seq2)
seq1.each do |x|
seq2.each do |y|
yield [x,y]
end
end
end
Callable like this:
prod (1..2), (1..2) do |prod| p prod end
The yield supplies the product for each run of the inner loop, and the yielded value is printed by the block supplied by the caller.
What exactly do you not understand here? You've made an iterator that yields all possible pairs of elements. If you pass CartProd#each a block, it will be executed a.length*b.length times. It's like having two different for cycles folded one into another in any other programming language.
yield simply passes (yields) control to a block of code that has been passed in as part of the method call. The values after the yield keyword are passed into the block as arguments. Once the block has finished execution it passes back control.
So, in your example you could call #each like this:
CartProd.new([1, 2], [3, 4]).each do |pair|
# control is yielded to this block
p pair
# control is returned at end of block
end
This would output each pair of values.
I'm looking for a way to do the following in Ruby in a cleaner way:
class Array
def find_index_with_offset(offset, &block)
[offset..-1].find &block
end
end
offset = array.find_index {|element| element.meets_some_criterion?}
the_object_I_want =
array.find_index_with_offset(offset+1) {|element| element.meets_another_criterion?}
So I'm searching a Ruby array for the index of some object and then I do a follow-up search to find the first object that matches some other criterion and has a higher index in the array. Is there a better way to do this?
What do I mean by cleaner: something that doesn't involve explicitly slicing the array. When you do this a couple of times, calculating the slicing indices gets messy fast. I'd like to keep operating on the original array. It's easier to understand and less error-prone.
NB. In my actual code I haven't monkey-patched Array, but I want to draw attention to the fact that I expect I'm duplicating existing functionality of Array/Enumerable
Edits
Fixed location of offset + 1 as per Mladen Jablanović's comment; rewrite error
Added explanation of 'cleaner' as per Mladen Jablanović's comment
Cleaner is here obviously subjective matter. If you aim for short, I don't think you could do better than that. If you want to be able to chain multiple such finds, or you are bothered by slicing, you can do something like this:
module Enumerable
def find_multi *procs
return nil if procs.empty?
find do |e|
if procs.first.call(e)
procs.shift
next true if procs.empty?
end
false
end
end
end
a = (1..10).to_a
p a.find_multi(lambda{|e| e % 5 == 0}, lambda{|e| e % 3 == 0}, lambda{|e| e % 4 == 0})
#=> 8
Edit: And if you're not concerned with the performance you could do something like:
array.drop_while{|element|
!element.meets_some_criterion?
}.drop(1).find{|element|
element.meets_another_criterion?
}
My background is in PHP and C#, but I'd really like to learn RoR. To that end, I've started reading the official documentation. I have some questions about some code examples.
The first is with iterators:
class Array
def inject(n)
each { |value| n = yield(n, value) }
n
end
def sum
inject(0) { |n, value| n + value }
end
def product
inject(1) { |n, value| n * value }
end
end
I understand that yield means "execute the associated block here." What's throwing me is the |value| n = part of the each. The other blocks make more sense to me as they seem to mimic C# style lambdas:
public int sum(int n, int value)
{
return Inject((n, value) => n + value);
}
But the first example is confusing to me.
The other is with symbols. When would I want to use them? And why can't I do something like:
class Example
attr_reader #member
# more code
end
In the inject or reduce method, n represents an accumulated value; this means the result of every iteration is accumulated in the n variable. This could be, as is in your example, the sum or product of the elements in the array.
yield returns the result of the block, which is stored in n and used in the next iterations. This is what makes the result "cumulative."
a = [ 1, 2, 3 ]
a.sum # inject(0) { |n, v| n + v }
# n == 0; n = 0 + 1
# n == 1; n = 1 + 2
# n == 3; n = 3 + 3
=> 6
Also, to compute the sum you could also have written a.reduce :+. This works for any binary operation. If your method is named symbol, writing a.reduce :symbol is the same as writing a.reduce { |n, v| n.symbol v }.
attr and company are actually methods. Under the hood, they dynamically define the methods for you. It uses the symbol you passed to work out the names of the instance variable and the methods. :member results in the #member instance variable and the member and member = methods.
The reason you can't write attr_reader #member is because #member isn't an object in itself, nor can it be converted to a symbol; it actually tells ruby to fetch the value of the instance variable #member of the self object, which, at class scope, is the class itself.
To illustrate:
class Example
#member = :member
attr_accessor #member
end
e = Example.new
e.member = :value
e.member
=> :value
Remember that accessing unset instance variables yields nil, and since the attr method family accepts only symbols, you get: TypeError: nil is not a symbol.
Regarding Symbol usage, you can sort of use them like strings. They make excellent hash keys because equal symbols always refer to the same object, unlike strings.
:a.object_id == :a.object_id
=> true
'a'.object_id == 'a'.object_id
=> false
They're also commonly used to refer to method names, and can actually be converted to Procs, which can be passed to methods. This is what allows us to write things like array.map &:to_s.
Check out this article for more interpretations of the symbol.
For the definition of inject, you're basically setting up chained blocks. Specifically, the variable n in {|value| n = yield(n, value)} is essentially an accumulator for the block passed to inject. So, for example, for the definition of product, inject(1) {|value| n * value}, let's assume you have an array my_array = [1, 2, 3, 4]. When you call my_array.product, you start by calling inject with n = 1. each yields to the block defined in inject, which in turns yields to the block passed to inject itself with n (1) and the first value in the array (1 as well, in this case). This block, {|n, value| n * value} returns 1 == 1 * 1, which is set it inject's n variable. Next, 2 is yielded from each, and the block defined in inject block yields as yield(1, 2), which returns 2 and assigns it to n. Next 3 is yielded from each, the block yields the values (2, 3) and returns 6, which is stored in n for the next value, and so forth. Essentially, tracking the overall value agnostic of the calculation being performed in the specialised routines (sum and product) allows for generalization. Without that, you'd have to declare e.g.
def sum
n = 0
each {|val| n += val}
end
def product
n = 1
each {|val| n *= val}
end
which is annoyingly repetitive.
For your second question, attr_reader and its family are themselves methods that are defining the appropriate accessor routines using define_method internally, in a process called metaprogramming; they are not language statements, but just plain old methods. These functions expect to passed a symbol (or, perhaps, a string) that gives the name of the accessors you're creating. You could, in theory, use instance variables such as #member here, though it would be the value to which #member points that would be passed in and used in define_method. For an example of how these are implemented, this page shows some examples of attr_* methods.
def inject(accumulator)
each { |value| accumulator = yield(accumulator, value) }
accumulator
end
This is just yielding the current value of accumulator and the array item to inject's block and then storing the result back into accumulator again.
class Example
attr_reader #member
end
attr_reader is just a method whose argument is the name of the accessor you want to setup. So, in a contrived way you could do
class Example
#ivar_name = 'foo'
attr_reader #ivar_name
end
to create an getter method called foo
Your confusion with the first example may be due to your reading |value| n as a single expression, but it isn't.
This reformatted version might be clearer to you:
def inject(n)
each do |value|
n = yield(n, value)
end
return n
end
value is an element in the array, and it is yielded with n to whatever block is passed to inject, the result of which is set to n. If that's not clear, read up on the each method, which takes a block and yields each item in the array to it. Then it should be clearer how the accumulation works.
attr_reader is less weird when you consider that it is a method for generating accessor methods. It's not an accessor in itself. It doesn't need to deal with the #member variable's value, just its name. :member is just the interned version of the string 'member', which is the name of the variable.
You can think of symbols as lighter weight strings, with the additional bonus that every equal label is the same object - :foo.object_id == :foo.object_id, whereas 'foo'.object_id != 'foo'.object_id, because each 'foo' is a new object. You can try that for yourself in irb. Think of them as labels, or primitive strings. They're surprisingly useful and come up a lot, e.g. for metaprogramming or as keys in hashes. As pointed out elsewhere, calling object.send :foo is the same as calling object.foo
It's probably worth reading some early chapters from the 'pickaxe' book to learn some more ruby, it will help you understand and appreciate the extra stuff rails adds.
First you need to understand where to use symbols and where its not..
Symbol is especially used to represent something. Ex: :name, :age like that. Here we are not going to perform any operations using this.
String are used only for data processing. Ex: 'a = name'. Here I gonna use this variable 'a' further for other string operations in ruby.
Moreover, symbol is more memory efficient than strings and it is immutable. That's why ruby developer's prefers symbols than string.
You can even use inject method to calculate sum as (1..5).to_a.inject(:+)
A snippet of my code below flips a coin and outputs a result of 10 total heads or tails.
(e.g. Heads Tails Heads Tails...)
I'd like to store this into a variable where I can put it into an array and use its strings.
%w[act] only outputs the string "act". How can I get that line of code to output my array of strings from the line act = coin.flip?
Updated and added full code
class Coin
def flip
flip = 1 + rand(2)
if flip == 2
then puts "Heads"
else
puts "Tails"
end
end
end
array = []
10.times do
coin = Coin.new
array << coin.flip
end
puts array
This:
10.times do
coin = Coin.new
act = coin.flip
end
doesn't produce an array. It simply creates ten coin flips and throws them all away, the result of that expression is, in fact, 10. If you want an array, you'll need to build one.
You could take Douglas's approach or try something a bit more idiomatic.
The Integer#times method returns an enumerator so you can use any of the Enumerable methods on it rather than directly handing it a block. In particular, you could use collect to build an array in one nice short piece of code:
a = 10.times.collect { Coin.new.flip }
That gives you 10 flips in the Array a and then you can puts a or puts a.join(', ') or whatever you want.
The %w[] won't work because that's for generating an Array of whitespace separated words:
%w[] Non-interpolated Array of words, separated by whitespace
So %w[a b c] is just a nicer way of saying ['a', 'b', 'c'] and the words within %w[] are treated as single quoted strings rather than variables or method calls to be evaluated.
Seems that there is some editing going on. You'll also want to modify your flip method to return the flip rather than print it:
def flip
flip = 1 + rand(2)
if flip == 2
"Heads"
else
"Tails"
end
end
Then you'll get your Heads and Rails in the array.
Put the act results into an array.
arr = []
10.times do
coin = Coin.new
arr << coin.flip
end
p arr # => [...]