What does :^ in reduce method mean? - ruby

I was doing a challenge on Code Wars where I was given an array "numbers" with several (sometimes repeating) integers and I had to return one unique integer. I passed the challenge but when I looked at all the previously submitted solutions, I noticed this reduce method:
def stray (numbers)
numbers.reduce(&:^)
end
I know what reduce method generally does but I haven't been able to find what the symbol ^ means. Could anyone please let me know its purpose?

The reduce method is used on arrays to combine all elements of that array into a single item.
The reduce method accepts a starting value and a block of code.
What you are using is a shorthand version of reduce which means the following:
numbers.reduce(&:^)
The & character will attempt to call the method on the argument itself when it is used as a last argument of a method call or definition. The ^ character signifies the bitwise XOR operator.
Inject is also an alias for reduce in Ruby.
You can read more here.

Related

Ruby: Add value to Variable and Clamp/limit the Variable in one line

Suppose I have several arrays in Ruby which I add/subtract values and afterwards I limit their range, like so:
array[x][y]=array[x][y]+1
array[x][y]=array[x][y].clamp (0..99)
Since I have many different arrays with rather long (index) names - and in order not to repeat those names twice in one line, I'd like to achieve something like
array[x][y]+=1.clamp (0..99)
Which is accepted by the interpreter, but doesn't work. It adds, but the value in the array does not get clamped.
Splitting it in at least two lines
array[x][y]+=1
array[x][y].clamp(0..99)
does also add, but doesn't clamp.
Is there any solution for this to fit the entire command in one line?
Many thanks!
The #clamp method doesn't take a range as a single argument for Ruby versions before 2.7, but rather two arguments representing the min and max, and #clamp does not mutate the object it's called on.
array[x][y] = (array[x][y] + 1).clamp(0, 99)
Note that because it's valid to call a method without parentheses, if parentheses are used around an argument list, there should not be any space between the method name and the parentheses. E.g. 1.clamp(0..4) rather than 1.clamp (0..4).

What does :^ stand for in Ruby?

Not sure if I am searching in a wrong way, but couldn't find the answer anywhere online...
What does :^ stand for in Ruby? In particular trying to understand the code below:
# this returns the element in array_of_numbers, which occurs an odd number of times
array_of_numbers.reduce(:^)
# this returns 0
[1,2,3].reduce(:^)
# this returns 4
[1,2,3,4].reduce(:^)
Was tying to understand the logic playing with different arrays, but I think I am missing something. Thanks in advance!
: in front of a name produces a Symbol.
In some contexts, a Symbol can be used as a message to an object. The object that receives the message reacts to it by calling its method that has the same name as the symbol (if such a method exists).
In your examples, this method is Integer#^, which represent the exclusive OR bit operator.
[1,2,3].reduce(:^) is, more or less, the same as 1 ^ 2 ^ 3.*
Being an OOP language, 1 ^ 2 ^ 3 in Ruby is syntactic sugar for (1.^(2)).^(3).
Read more about the exclusive OR bit operator.
* They produce the same result but the explicit expression should be faster.

ARGV in Ruby: The Meaning of a Constant

I am new to Ruby, so please bear my questions in case they might not make any sense. My question is,
A constant is where we assign values that should not be altered. Why is ARGV a constant, when we can pass as many arguments as we want to in it? Are the arguments not the values for ARGV? When we pass arguments to ARGV, are we assigning values or does ARGV already have its own sets of values?
A constant has to have its value newly assigned at some point. If you take the meaning of constant as something that is never newly assigned its value, then there would be no constant at all. A constant is therefore, a relative notion; you cannot define what a constant is without the relevant domain/scope. A constant remains consistant within that domain, but has its value assigned/changed outside of the scope.
In mathematics, suppose some mathematician used a constant A = 3 at some point in their life solving a certain problem. That does not mean that everyone from that point on using the constant A would always have to assume its value to be 3. In mathematics, the domain of a constant can be a single proof, an article, a book, or a convention throughout a subfield, etc.
For a computer program, the domain for a constant is usually the execution lifespan of a program. A constant remains constant relative to the execution of the program. ARGV has its values set prior to the execution of the Ruby program.
The point is that ARGV has constant value for the entire time span your program runs. Another reason is that you are not supposed to change the value of ARGV. From the Wikipedia page titled Constant (computer programming):
[…] a constant is an identifier whose associated value cannot typically be altered by the program during its execution […]
Ruby is a bit special because it allows you to reassign ARGV (as any other constant), although it will issue a warning. The following is valid Ruby code (but please don’t do this):
ARGV = [123]
# warning: already initialized constant ARGV
p ARGV
# [123]
ARGV is a constant array that is defined on initialization of a Ruby script, in which the values in that array are set to the arguments which were passed in to the script itself.
From the ARGF documentation:
ARGF is a stream designed for use in scripts that process files given as command-line arguments or passed in via STDIN.
The arguments passed to your script are stored in the ARGV Array, one argument per element. ARGF assumes that any arguments that aren't filenames have been removed from ARGV
See the documentation for ARGV for more details.

Sum array of numbers [duplicate]

This question already has answers here:
How to sum array of numbers in Ruby?
(16 answers)
Closed 8 years ago.
Q: Write a method, sum which takes an array of numbers and returns the sum of the numbers.
A:
def sum(nums)
total = 0
i = 0
while i < nums.count
total += nums[i]
i += 1
end
# return total
total
end
There has to be another way to solve this without using while, right? Anyone know how?
Edit: This is not an exam or test. This is a practice problem provided on github for app academy. They provide the question and answer as an example. I just read however that good programmers don't like to use while or unless, so I was curious if I could learn something to solve this problem a better way. Like with enumerable? (Noob at Ruby here, obviously..)
Also, I would love any walkthrough or methods that I should learn.. This question is also different because I am asking for specific examples using this data.
The usual way of doing that would be this:
def sum(nums) nums.reduce(&:+) end
which is short for something like this:
def sum(nums) nums.reduce(0) { |total, num| total + num } end
I see that Neil posted a similar solution while I was typing this, so I'll just note that reduce and inject are two names for the same method - Ruby has several aliases like this so that people used to different other languages can find what they're looking for. He also left off the &, which is optional when using a named method for reduce/inject, but not in other cases.
Explanation follows.
In Ruby you don't normally use explicit loops (for, while, etc.). Instead you call methods on the collection you're iterating over, and pass them a block of code to execute on each item. Ruby's syntax places the block after the arguments to the method, between either do...end or {...}, so it looks like traditional imperative flow control, but it works differently.
The basic iteration method is each:
[1,2,3].each do |i| puts i end
That calls the block do |i| puts i end three times, passing it 1, then passing it 2, and finally passing it 3. The |i| is a block parameter, which tells Ruby where to put the value(s) passed into the block each time.
But each just throws away the return value of the block calls (in this case, the three nils returned by puts). If you want to do something with those return values, you have to call a different method. For example, map returns an array of the return values:
[1,2,3].map do |i| puts i end
#=> [nil, nil, nil]
That's not very interesting here, but it becomes more useful if the block returns something:
[1,2,3].map do |i| 2*i end
#=> [2,4,6]
If you want to combine the results into a single aggregate return value instead of getting back an array that's the same size as the input, that's when you reach for reduce. In addition to a block, it takes an extra argument, and the block itself is also called with an extra argument. The extra parameter corresponding to this argument is called the "accumulator"; the first time the block is called, it gets the argument originally passed to reduce, but from then on, it gets the return value of the previous call to the block, which is how each block call can pass information along to the next.
That makes reduce more general than map; in fact, you can build map out of reduce by passing in an empty array and having the block add to it:
[1,2,3].reduce([]) do |a,i| a + [2*i] end
#=> [2,4,6]
But since map is already defined, you would normally just use it for that, and only use reduce to do things that are more, well, reductive:
[1,2,3].reduce(0) do |s, i| s + 2*i end
#=> 12
...which is what we're doing in solving your problem.
Neil and I took a couple extra shortcuts. First, if a block does nothing but call a single method on its parameters and return the result, you can get an equivalent block by prefixing &: to the method name. That is, this:
some_array.reduce(x) do |a,b| a.some_method(b) end
can be rewritten more simply as this:
some_array.reduce(x, &:some_method)
and since a + b in Ruby is really just a more-familiar way of writing the method call a.+(b), that means that you can add up numbers by just passing in &:+:
[1,2,3].reduce(0, &:+)
#=> 6
Next, the initial accumulator value for reduce is optional; if you leave it out, then the first time the block is called, it gets the first two elements of the array. So you can leave off the 0:
[1,2,3].reduce(&:+)
#=> 6
Finally, you normally need the & any time you are passing in a block that is not a literal chunk of code. You can turn blocks into Proc objects and store them in variables and in general treat them like any other value, including passing them as regular arguments to method calls. So when you want to use one as the block on a method call instead, you indicate that with the &.
Some methods, including reduce, will also accept a bare Symbol (like :+) and create the Proc/block for you; and Neil took advantage of that fact. But other iterator methods, such as map, don't work that way:
irb(main):001:0> [-1,2,-3].map(:abs)
ArgumentError: wrong number of arguments (1 for 0)
from (irb):1:in `map'
from (irb):1
from /usr/bin/irb:12:in `<main>'
So I just always use the &.
irb(main):002:0> [-1,2,-3].map(&:abs)
#=> [1, 2, 3]
There are lots of good online tutorials for Ruby. For more general information about map/reduce and related concepts, and how to apply them to problem-solving, you should search for introductions to "functional programming", which is called that because it treats "functions" (that is, blocks of executable code, which in Ruby are realized as Proc objects) as values just like numbers and strings, which can be passed around, assigned to variables, etc.
Probably the most idiomatic way of doing this in Ruby is:
nums.inject(:+)
. . . although this basically hides all the working, so it depends what the test is trying to test.
Documentation for Array#inject

How does "(1..4).inject(&:+)" work in Ruby

I find this code in Ruby to be pretty intriguing
(1..4).inject(&:+)
Ok, I know what inject does, and I know this code is basically equivalent to
(1..4).inject(0) {|a,n| a + n}
but how exactly does it work?
Why &:+ is the same as writing the block {|a,n| a + n}?
Why it doesn't need an initial value? I'm ok with the inicial value being 0, but (1..4).inject(&:*) also works, and there the initial value must be 1...
From Ruby documentation:
If you specify a symbol instead, then each element in the collection will be passed to the named method of memo
So, specifying a symbol is equivalent to passing the following block:
{|memo, a| memo.send(sym, a)}
If you do not explicitly specify an initial value for memo, then uses the first element of collection is used as the initial value of memo.
So, there is no magic, Ruby simply takes the first element as the initial value and starts injecting from the second element. You can check it by writing [].inject(:+): it returns nil as opposed to [].inject(0, :+) which returns 0.
Edit: I didn't notice the ampersand. You don't need it, inject will work with a symbol. But if you do write it, the symbol is converted to block, it can be useful with other methods

Resources