Why does this method return three values? - ruby

I have following Ruby programm:
def swap (a,b)
return a,b = b,a
end
puts swap(5,3)
I expected the output.
3
5
But I get.
5
3
5
What's the reason?
Thanks!

Why does this method return three values?
It's because of the return statement, Ruby tries to interpret the right-hand side as an array and your code:
return a,b = b,a
gets evaluated as: (parentheses added for clarity)
return [a, (b=b), a]
i.e. a 3-element array [a, b, a] (assigning b to itself does nothing)

Remove the keyword return. It is actually doing: return a, (b), a. Where (b = b)
def swap(a,b)
a, b = b, a
end
puts swap(5,3)
Output
=> 3, 5

In your program: in swap function the return you have given is return a,b = b,a
remove a,band diretcly write return b,a.
you will get your expected output.
Reason:
in return a,b = b,a is return first the value of a then executing b=b,a.
Hope this might help you out
def swap (a,b)
return b,a
end
puts swap(5,3)
Output
3
5

Related

Create a function that returns the total number of smiley faces

I've been working on a task to create a function that returns the total number of smiley faces. Valid smiley faces look like: ":) :D ;-D :~)" and invalid smiling faces: ";( :> :} :] ".
So far this is how my answer looks:
def count_smileys(arr)
arr.to_s.count(":)", ":D", ";-D", ":~")
end
The only positive test my code returns:
Test Passed: Value == 0
Expected: 4, instead got: 0
Expected: 2, instead got: 0
Expected: 1, instead got: 0
What am I doing wrong and how can I fix it?
As the documentation for String#count says, each individual argument to String#count defines a set of characters, and the final set of characters to count is the intersection of all those sets.
In your case, the intersection is empty, therefore you are counting nothing:
:) is the set { :, ) }
:D is the set { :, D }
;-D is the set of characters starting with ; and ending with D, i.e. { ;, <, =, >, ?, #, A, B, C, D }
:~ is the set { :, ~ }
So, the intersection of all of those sets is
{ :, ) } ∩ { :, D } ∩ { ;, <, =, >, ?, #, A, B, C, D } ∩ { :, ~ }
= { : } ∩ { ;, <, =, >, ?, #, A, B, C, D } ∩ { :, ~ }
= ∅ ∩ { :, ~ }
= ∅
i.e. the empty set.
Very good answer by Jörg.
To also provide a possible solution. You don't need to cast this to a string, as array also has a count method which accepts a block.
def count_smileys(arr)
array.count do |element|
[":)", ":D", ";-D", ":~"].include?(element)
end
end
https://makandracards.com/makandra/31141-ruby-counting-occurrences-of-an-item-in-an-array-enumerable

something like pattern matching list in prolog

[A,B,C|_] = [1,2,3,4,5,6,7]
A = 1
B = 2
C = 3.
I expected this result. However, when I have:
L = [A,B,C,D]
how to do:
L = [1,2,3,4,5,6,7]
A = 1
B = 2
C = 3
D = 4
?
The problem is that I don't know how long is L. Only thing that I know: L is shorter than rightside list and L contains only variables.
We just "insert the free variable" at the variables list's tail, append(Vars, _, ExtendedList), and then pattern match, ExtendedList = Data. Contracting, we get:
match_vars(Vars, Data):-
append(Vars, _, Data).
Testing:
2 ?- match_vars([A,B],[1,2,3,4,5]).
A = 1,
B = 2.
3 ?- match_vars([A,B,C,D],[1,2,3,4,5]).
A = 1,
B = 2,
C = 3,
D = 4.
4 ?-
(using append/3 was already mentioned in the comments).

Equality test on three or more objects

If I have three or more objects like so:
a = 4
b = 4
c = 4
d = 2
what would be a clean ruby-style way of determining whether they are all equal? Any bespoke methods for running equality tests on three or more elements?
I suppose I could do something like this:
arrays = [a,b,c,d].map{|x| [x]}
arrays.first == arrays.reduce(:&) ? true : false
which appears to work, but feels sort of ham handed, and might be difficult for other developers to read.
[a,b,c,d].any?{|x| x != a}
or
array.any?{|x| x != array.first}
Alternatively, the #all? method may read more intuitively for some:
array.all? {|x| x == array.first }
[a, b, c, d].group_by(&:itself).length == 1
# => false
or
[a, b, c, d].chunk(&:itself).to_a.length == 1
# => false
or
[a, b, c, d].chunk_while(&:==).to_a.length == 1
# => false
or the naive:
[a, b, c, d].uniq.length == 1
I was reminded of one?. Provided that you do not have any falsy element, the above can be written:
[a, b, c, d].uniq.length.one?
I think the answer by #kipar is better by all means, but for the sake of “doing it the way you started” I would post this here:
[a, b, c, d].reduce { |r, e| r == e && r } && true

Why can't I compare two atom like this?

So basically here is some Prolog code I wrote, using GNU-Prolog 1.4.4.
A is 1,
B = (A == 2),
B == no.
A is 2,
B = (A == 2),
B == no.
What I am expecting is when A is 2, then B == no returns no, when A is 1, then B == no returns yes.
However, to my surprise, both two code snippets return no, which leaving me the impression that B == no works in an unexpected way..
So basically how can I write the code in the way I want?
Could anyone give me some help?
The line
B = (A == 2)
does not compute A==2 in any way and assign the result to B. It just unifies the term B (a variable) with the term (A==2). The result of the unification is that B is now A==2. You can check yourself by omitting B==no:
?- A is 1, B=(A==2).
A = 1,
B = (1==2) ?
yes
If you really want that B unifies with the atoms yes resp. no you can use an if-then-else construct:
( A == 2 -> B = yes
; otherwise -> B = no)

How to initialize objects with different object_id in Ruby?

If I initialize objects with assignment like a = b = c = []
then this variables have the same object_ids: a.object_id == b.object_id == c.object_id
Also I tried:
[a, b, c].map {|e| e = [] }
a, b, c = Array.new(3, [])
a, b, c = Array.new(3, Array.new)
but it doensn't initialize a, b, c variables with different object_ids
Is there a way to initialize variables a, b, c with different object ids but with the same value == []?
How about these possible solutions:
a,b,c=[],[],[]
a,b,c=(0..2).map{[]}
a,b,c=Array.new(3){[]}
How about this?
a = []
b = []
c = []

Resources