The loop prints 23401, but the last line does not print:
[2,3,4,0,1].each do |value|
print value if value==2...value==2
end
print true if 3==2...3==2
I wonder what the problem is
I've tried a lot of loops, and I've found that conditions are always true once they're true
This value==2...value==2 might look like a standard Range; however the syntax of if (condition)...(condition) is actually a control expression called a Flip-Flop.
The form of the flip-flop is an expression that indicates when the flip-flop turns on, .. (or ...), then an expression that indicates when the flip-flop will turn off. While the flip-flop is on it will continue to evaluate to true, and false when off.
There are 2 forms 2 dots (..) and 3 dots (...).
2 dots (..) means: "...the off condition is evaluated when the on condition changes."; and
3 dots (...) means: "...the off condition is evaluated on the following iterations"
2 dots form (..) of the flip-flop
[2, 3, 4, 0, 1].each do |value|
print value if (value == 2)..(value == 2)
end
# 2
Because the first iteration turns on the flip-flop for only this iteration e.g. left hand side (on) 2 == 2 and the right hand side (off) 2 == 2 so it turns on, evaluates, and turns off in the same iteration.
3 dots form (...) of the flip-flop as in your example
[2, 3, 4, 0, 1].each do |value|
print value if (value == 2)...(value == 2)
end
# 23401
Because the first iteration turns on the flip-flop e.g. left hand side (on) 2 == 2 but the right hand side (off) value == 2 is not evaluated until the following iterations and since no other elements in the array satisfy value == 2 it does not turn off.
If there were another element that satisfied the off condition in your array:
[2, 3, 4, 2, 0, 1].each {|value| print(value) if (value == 2)...(value == 2) }
# 2342
Additional
...but the last line does not print:
Your last line does not print because the left hand side (3 == 2) is false so the flip-flop does not turn on (Additionally using a flip-flop outside of a loop makes no real sense).
Related
I've tried different ways and this is probably the closest that I got to it. I am trying to write a method that takes in an array of strings and returns it containing the strings that are at least 5 characters long and end with "y".
I'm a beginner and this is my second problem I've come across with, and I've tried multiple if statements and using a while loop, however I could not get to it and now this is where I am at. Thank you!
def phrases(arr1, arr2)
arr1 = ["funny", "tidy", "fish", "foogiliously"]
arr2 = ["happily", "lovely", "hello", "multivitaminly"]
if (arr1.length > 5 && arr1.length == "y")
return arr1
elsif (arr2.length > 5 && arr2.length == "y")
return arr2
end
end
puts phrases(["funny", "tidy", "fish", "foogiliously"])
puts phrases(["happily", "lovely", "hello", "multivitaminly"])
If I'm understanding your question correctly, you want to return a subset of the passed in array matching your conditions (length ≥ 5 and last character = 'y'). In that case:
def phrases(words)
words.grep(/.{4}y\z/)
end
What that regex does:
.{4} means 4 of any character
y is the letter y
\z is the end of the string, so we don't match in the middle of a long word
The docs for Enumerable#select are here (an Array is an Enumerable).
Output:
> phrases(["funny", "tidy", "fish", "foogiliously"])
=> ["funny", "foogiliously"]
> phrases(["happily", "lovely", "hello", "multivitaminly"])
=> ["happily", "lovely", "multivitaminly"]
If you only want word characters, rather than any character, you'd use this regex instead: /\A.{4,}y\z/. In that case, \A means the start of the string, and \w{4,} means at least 4 word characters.
If, when given an array and inclusion criterion, one wishes to construct an array that contains those elements of the first array that satisfy the inclusion criterion, one generally uses the method Array#select or Array#reject, whichever is more more convenient.
Suppose arr is a variable that holds the given array and include_element? is a method that takes one argument, an element of arr, and returns true or false, depending on whether the inclusion criterion is satisified for that element. For example, say the array comprises the integers 1 through 6 and the inclusion criterion is that the number is even (2, 4 and 6). We could write:
arr = [1,2,3,4,5,6]
def include_element?(e)
e.even?
end
include_element?(2)
#=> true
include_element?(3)
#=> false
arr.select { |e| include_element?(e) }
#=> [2, 4, 6]
The method include_element? is so short we probably would substitute it out and just write:
arr.select { |e| e.even? }
Array#select passes each element of its receiver, arr, to select's block, assigns the block variable e to that value and evaluates the expression in the block (which could be many lines, of course). Here that expresssion is just e.even?, which returns true or false. (See Integer#even? and Integer#odd?.)
If that expression evaluates as a truthy value, the element e is to be included in the array that is returned; if it evaluates as a falsy value, e is not to be included. Falsy values (logical false) are nil and false; truthy values (logical true) are all other Ruby objects, which of course includes true.
Notice that we could instead write:
arr.reject { |e| e.odd? }
Sometimes the inclusion criterion consists of a compound expression. For example, suppose the inclusion criterion were to keep elements of arr that are both even numbers and are at least 4. We would write:
arr.select { |e| e.even? && e >= 4 }
#=> [4, 6]
With other criteria we might write:
arr.select { |e| e.even? || e >= 4 }
#=> [2, 4, 5, 6]
or
arr.select { |e| e < 2 || (e > 3 && e < 6) }
#=> [1, 4, 5]
&& (logical 'and') and || (logical 'or') are operators (search "operator expressions"). As explained at the link, most Ruby operators are actually methods, but these two are among a few that are not.
Your problem now reduces to the following:
arr.select { |str| <length of str is at least 5> && <last character of str is 'y'> }
You should be able to supply code for the <...> bits.
You are trying to write a function that should work on a single array at a time I think. Also, you are taking in an array, and retaining only those elements that satisfy your conditions: at least 5 characters long, and ends with y. This is a filtering operation. Read about the methods available for ruby's Array class here
def phrases(array)
...
filtered_array
end
Now the condition you are using is this arr1.length > 5 && arr1.length == "y".
The first half should check if the string length is greater than 5, not the array length itself. The second half is an indexing operation, and your code for that is incorrect. basically you are checking if the last character in the string is y.
Usually strings are indexed in this manner: string[index]. In your case you can use string[-1]=='y' or string[string.length - 1]=='y'. This because arrays and strings are zero indexed in ruby. The first element has index of 0, the second has an index of 1, and the last one, therefore, will have an index of length-1. If you use negative indexes then the array is indexed from the end, so string[-1] is a quick way to get to the last element.
Considering this, the function will take the following structure:
def phrases(array)
filtered_array = [] # an empty array
loop through the input array
for each element check for the condition element.length > 5 && element[-1]=='y'
if true: push the element into the filtered_array
once the loop is done, return the filtered array
end
Read about ruby arrays, the methods push, filter and select in the above linked documentation to get a better idea. I'd also recommend the codeacademy ruby tutorial.
Edit: Both halves of the condition are incorrect. I had overlooked a mistake in my earlier answer. arr1.length refers to the length of the array. You want to check the length of each string in the array. So in your for loop you should check the length of the loop variable, if that is greater than 5.
You may want to spend some time reading about the methods in the core library, especially String#end_with? and Enumerable#select. You could then write a method that'd contain something like this:
['abc', 'qwerty', 'asdfghjk', 'y'].select{|s| s.length >= 5}.select{|s| s.end_with? 'y'}
#=> ["qwerty"]
This part of code calculates the value of each arithmetic series up to and including the number that the user put in:
print "enter a number: "
num = gets.to_i
(1..num).inject(0) do |res, e|
res += e
p res
end
I think that (1..num) is the range, with num being the user input. I know that inject combines all elements of enum by applying a binary operation specified by a block or a symbol that names a method or operator.
I don't understand what each element in this line does:
(1..num).inject(0) do |res, e|
What does |res, e| mean? It must be the block that defines what inject does, but what does for instance res and e stand for? (e is probably element?)
What does (0) stand for?
What does the command do do?
what is its connection in regard to (1..num) and inject(0)?
Am I right to assume that p at the end just stands for puts or print?
inject takes an optional start value, and a block taking an intermediate value and element and returning a new intermediate value.
So:
What does (0) stand for?
The start value parameter to inject.
What does the command "do" do?
It is not a command; it marks the start of the block (terminated by end). .inject(0) do ... end is almost (except for some syntactic issues) the same as .inject(0) { ... }. Usually, do ... end is used for multi-line blocks and { ... } for single-line blocks, but it is not a rule.
What does |res, e| mean?
Those are the block parameters (intermediate value and current element), here probably called after "result" and "element", respectively.
Let's see on a simplified example: (1..3).inject(0) do |res, e| res + e end will set the intermediate result to 0. Then it will pass this intermediate result and the first element of the enumerable being injected: res is 0 and e is 1. The value of the block is the value of its last expression, which is 1 (result of 0 + 1). This 1 now becomes the new intermediate value, and 2 becomes the next current element. The value of the block is 3 (result of 1 + 2). In the next iteration, intermediate value is 3, and the current element also 3, resulting in 6 (3 + 3). The range will stop yielding elements now that we reached its upper boundary, and inject returns with the last intermediate result calculated, 6.
Also, the last question am I right to assume that "p" at the end just stands for puts or print?
Almost. p is its own beast. p x is roughly synonymous with puts x.inspect; x - i.e. it prints the value in a bit different format, and unlike puts which always returns nil, p returns the value unchanged. Thus, p res at the end of your block will not destroy the code by making it return nil, but transparently return res.
inject is a method that boils a collection (eg an array or range) down to a single value. It does this by executing the block once for each element in the collection. The block takes two arguments: the current value being worked on, and the single value that will eventually be returned. inject itself takes one argument (aside from the block), which is its initial starting value.
Take this example.
x = [1, 2, 3, 4, 5].inject(0) do |result, current|
result + current
end
We have a list of numbers, [1, 2, 3, 4, 5]. We're going to boil them down into one single number.
We start with 0, because that's inject's argument. That means that the first time the block runs, result will be 0.
So the block runs for the first time. result is 0, current is 1, the first element. We say result + current (which is 1). It's the last expression inside the block, so it's what that block 'returns'.
At the end of the block, inject says "Okay, do we have more elements in the collection?" Yeah. So the block runs again. This time, result is whatever the last block returned, which was 1, and current is the second element, 2.
The block runs, and finishes with result + current, or 1 + 2, which is 3. There are still elements left, so we run again. This time, result is 3, and current is 3. result + current, 6. Still more values to go, on the next run result is 6 and current is 4. 6 + 4 = 10. Still more values to go, on the next run result is 10 and current is 5. 10 + 5 = 15.
Then the block finishes, and there are no more elements left. So inject itself returns with the final value, 15. So in the end, x = 15. We boiled down our list into one number by adding things up.
res in your example stands for result, and e for element. You can call them anything you want. You might call them sum while adding, or product if multiplying. But they don't have to be numbers. You could use inject to boil an array of strings, a range of characters, an array of arrays, whatever collection you want. The block just tells it how.
Excited to see that you're learning Ruby, welcome!
At your level of expertise best learn from a book.
Get yourself a copy of the "Pickaxe Book" — this is by far the best book.
The first edition fir Ruby 1.9 is available online, http://ruby-doc.com/docs/ProgrammingRuby
And here is a popular online tutorial, http://poignant.guide
Some quick answers
1..num is a range object
.inject(0) do ... end is a method call with TWO parameters, the value 0 and a code block
do |a, b| ... end is a code block with two parameters
res and e are VERY bad variable names, maybe better use sum and each?
p is a global method that prints debug information, similar to puts but not the same
Hope that helps to unblock you.
In Ruby, I would like to take an array of numbers, select 2 different numbers, add those 2 numbers together and see weather there equal to a variable x.y'd a variable x. Here is the code I used
def arrayIsEqual? (numArray, x)
return true if numArray.sample + numArray.sample == x
return false if numArray.empty? || numArray.count == 1
end
for example
numArray = [4,2,7,5]
x = 11
arrayIsEqual (numArray, n) should return true, since 4 + 7 = n(11)
How do I get this to work?
I don't want it to be 2 random numbers, just any 2 different numbers that add up to n
It looks like you're trying to see if there are any two numbers in the array that add up to the specified value x. However, your code just picks two numbers at random and checks if those numbers add up.
Ruby has the Array#combination method, which generates all combinations of a given length:
def contains_pair_for_sum?(arr, n)
!!arr.uniq.combination(2).detect { |a, b| a + b == n }
end
A few things to note:
First, we named it according to Ruby conventions: each word is separated_by_underscores. The ? on the end means that the method is a predicate method and returns a true or false value.
Inside the method, a few things happen. Let's look at that line, piece by piece.
arr: We take the array that was passed in.
<...>.uniq: We only look at the unique elements (because the OP wants to pick two different numbers).
<...>.combination(2): We ask for all combinations from the array of length 2. If the array was [4, 5, 6], we'd get [[4, 5], [4, 6], [5, 6]].
<...>.detect { |a, b| a + b == n }: We look for the first combination that adds up to n. If we found one, that's the result of that method. Otherwise, we get nil.
!!<...>: Finally, we take the result we got from detect and negate it twice. The first negation produces a Boolean value (true if the value we got was nil, or false if it's anything else); the second negation produces a Boolean value that's identical to the truth value of the first negation. This is a Ruby idiom to coerce a result into being either true or false.
Let's see it in action:
array = [4, 5, 9, 7, 8]
contains_pair_for_sum?(array, 11)
# => true (because [4, 7] sums to 11)
contains_pair_for_sum?(array, 17)
# => true (because [9, 8] sums to 17)
contains_pair_for_sum?(array, 100)
# => false (no pair matched)
I understand that your question is "is there any pair of numbers in my array equals x", in which case this will do what you need:
def has_pair_equal?(num_array, x)
(0..num_array.length-1).any? do |i|
num_array[i+1..-1].any? { |n| n + num_array[i] == x }
end
end
This checks all sums of pairs of numbers in the array, and checks if their sum is x. sample randomly picks an item from the array, which means that what your code does is "return true sometimes if there is a pair of numbers in my array equals x"
def array_is_equal? (num_array, x)
equality = 0
num_array.each do |a|
equality += 1 if a == x
return true if equality == 2
end
return false
end
Use lowercase and underscores for variables in Ruby. The convention is different here than in some other languages.
One liner
x=[4,2,7,5]; x.each_with_index.any? {|y,i| x.each_with_index.any? {|z,j| unless i==j; z+y==11; end } }
And as a function
def pair_sum_match?(arr, x)
arr.each_with_index.any? do |y,i|
arr.each_with_index.any? do |z,j|
unless i==j
z+y==x
end
end
end
end
Updated: Added each_with_index to avoid self inclusion on checks. It's a lot longer now :-/
Just iterate over it once and use the target number to see if it matches. 100 times faster then most of the answers here
numbers = ( -10..10 ).to_a
numbers.unshift( numbers.first + -1 ) # if you do -20 or 20
numbers.push( numbers.last + 1 )
target = 5
searched = { }
matches = { }
numbers.each do |number|
if searched[ target - number + 1 ] == true
matches[ "#{ number }_plus_#{ target - number }" ] = target
end
searched[ number + 1 ] = true
end
ap matches
I'm learning ruby and I got stuck with probable simple problem. There is the code:
str = 'abc'
a = 1
b = 2
a = str.reverse if str.size > 3
b = (str.reverse if str.size > 3)
p a
p b
Output:
1
nil
Can somebody tell me what these parentheses change in return value ? Is it kind of "block" of code ?
They are two different statements.
The first one is a conditional assignment:
a = str.reverse if str.size > 3
The if applies to the whole line. If str.size is not greater than 3, then absolutely nothing happens; a is not touched at all. You could also write it this way:
if str.size > 3 then
a = str.reverse
end
Being able to stick the if on the end just lets you do it in one line instead of a block.
The second one is an assignment of a conditional value.
b = (str.reverse if str.size > 3)
The value of b will always be changed in this case, no matter what; the value of str.size just determines what it is changed to. You could also use the block-form of if here:
b = if str.size > 3 then
str.reverse
end
The important difference is that the assignment to b happens outside the if, so it's not conditional; it always happens.
Parentheses don't create blocks, but they do determine precedence. Whenever you have a statement that could be interpreted multiple ways depending on the order in which things happen, what actually happens is determined by precedence rules. For instance, standard arithmetic rules tell us that this is true:
3 + 2 × 4 = 11
The answer isn't 20 because multiplication has precedence over addition. Parentheses let you change that; the above is equivalent to
3 + (2 × 4) = 11
and if you want the answer to be 20, then you could write this instead:
(3 + 2) × 4 = 20
Same thing goes for Ruby. Without parentheses, the first line is equivalent to this parenthesized version:
(a = str.reverse) if str.size > 3
which makes it clear that the assignment is what is guarded by the condition, not just the value being assigned.
Parentheses will change priority during operation.
Code between parenthesis will be evaluated as boolean due to its status as conditional expression.
Like #Mark Reed said, there are differents statements. And it is up to your intention to use the correct one. Hope it helped. ;)
So I am writing a Ruby program for school that changes the value of a boolean to true if a certain value is either 1 or 3, and to false if it is 0 or 2. Since I come from a Java background, I thought that this code should work: if n == 1 || n == 3
But it does not. So my question here is is it possible to use an "Or" expression thingy in If blocks in Ruby? I know that my current situation could be solved easily by just something like the following:
if n == 0
t_o_f = false
elsif n == 1
t_o_f = true
Et Cetera. But I want to know if I can use an Or in If blocks for the future.
Yes, any expression can be used in an if condition, including those using the || (logical or) operator.
As with Java, Ruby's || operator short-circuits. That is, if the left side is true, the right side is not evaluated.
Idiomatic ruby uses postfix if for one-liners:
puts "Yes" if n == 4 || n == 5
Avoid postfix if the line is long, however, and break it into multiple lines:
if n == 4 || n == 5
puts "This is a big long string to be output....................."
end
That's because postfix if can get visually lost at the end of a long line.
You can have a one-liner with prefix if, but it's not commonly seen:
if n == 4 || n == 5 then puts "foo" end
or, perhaps:
if n == 4 || n == 5 ; puts "foo" ; end
This is really a multi-line if condensed into one line; the semicolons act as line breaks.
When testing for multiple conditions, it can sometimes be valuable to use Array#include?:
puts "foo" if [4, 5].include?(n)
The value of this for only two conditions is not that great. For three or more, it reads well.
The or operator works, and you can write the keyword too:
if n==1 or n==2
end
http://www.tutorialspoint.com/ruby/ruby_operators.htm
And you could also write what you want this way:
x = (n%2) ? true : false
In addition to #Wayne Conrad: if there is little or no 'logic' deciding if n is true or false, then this is also a good option:
result = case n
when 1, 3 then true
when 0, 2 then false
end