brand new to Ruby, and love it. Just playing around with the below code:
public
def highest
highest_number = 0
each do |number|
number = number.to_i
highest_number = number if number > highest_number
puts highest_number
end
end
array = %w{1 2 4 5 3 8 22 929 1000 2}
array.highest
So at the moment the response I get is:
1
2
4
5
5
8
22
929
1000
1000
So it puts the array first, then the highest number from the array as well. However all I want it to is put the highest number only...
I have played around with this and can't figure it out! Sorry for such a newbie question
The problem is that you have the puts statement inside the each loop, so during every iteration it prints out what the highest number currently is. Try moving it outside the each loop so that you have this:
public
def highest
highest_number = 0
each do |number|
number = number.to_i
highest_number = number if number > highest_number
end
puts highest_number
end
array = %w{1 2 4 5 3 8 22 929 1000 2}
array.highest
Which produces the desired output:
1000
You could also save yourself some trouble by using max_by:
>> a = %w{1 2 4 5 3 8 22 929 1000 2}
=> ["1", "2", "4", "5", "3", "8", "22", "929", "1000", "2"]
>> m = a.max_by { |e| e.to_i }
=> "1000"
You could also use another version of max_by:
m = a.max_by(&:to_i)
to avoid the extra noise of the "block that just calls a method".
But this is probably a Ruby blocks learning exercise for you so using existing parts of the standard libraries doesn't count. OTOH, it is good to know what's in the standard libraries so punting to max_by or max would also count as a learning exercise.
You can do this instead and avoid the highest_number variable.
array = %w{1 2 4 5 3 8 22 929 1000 2}
class Array
def highest
collect { |x| x.to_i }. \
sort. \
last.to_i
end
end
array.highest # 1000
The collect { |x| x.to_i } can also be written as collect(&:to_i) in this case.
Related
I am trying to create a function that takes a string in it's parameters. It's supposed to determine the highest and lowest numeric values in the string and return them unchanged.
Here's my code:
def high_and_low(numbers)
numbers.split
numbers.each {|x| x.to_i}
return numbers.max().to_s, numbers.min().to_s
end
Here's the error:
main.rb:5:in `high_and_low': undefined method `each' for "4 5 29 54 4 0 -214 542 -64 1 -3 6 -6":String (NoMethodError)
from main.rb:8:in `<main>'
You have not changed the value from string to array.
Replace numbers.split with numbers = numbers.split.
Also you will need to change from numbers.each { |x| x.to_i } to numbers.map!(&:to_i). Otherwise you don't save integers anywhere.
BTW you don't have to use () and return (if it's in the end) so you can write [numbers.max.to_s, numbers.min.to_s].
Something like this should work:
def high_and_low(numbers)
numbers = numbers.split.map(&:to_i)
[numbers.max, numbers.min].map(&:to_s)
end
high_and_low("4 5 29 54 4 0 -214 542 -64 1 -3 6 -6") #=> ["542", "-214"]
And bonus (one liner, not that you should write code this way):
def high_and_low(numbers)
numbers.split.map(&:to_i).sort.values_at(-1, 0).map(&:to_s)
end
high_and_low("4 5 29 54 4 0 -214 542 -64 1 -3 6 -6") #=> ["542", "-214"]
The other answer is a good approach too so I include it here:
numbers.split.minmax_by { |n| -n.to_i }
Ruby has some nice methods available to make this much more simple:
"2 1 0 -1 -2".split.map(&:to_i).minmax
# => [-2, 2]
Breaking it down:
"2 1 0 -1 -2".split # => ["2", "1", "0", "-1", "-2"]
.map(&:to_i) # => [2, 1, 0, -1, -2]
.minmax # => [-2, 2]
If you want string versions of the values back, compare two integers in a block. minmax will return the values at the corresponding positions in the source array:
"2 1 0 -1 -2".split.minmax{ |a, b| a.to_i <=> b.to_i }
# => ["-2", "2"]
or:
"2 1 0 -1 -2".split.minmax_by{ |a| a.to_i }
# => ["-2", "2"]
minmax and minmax_by do the heavy lifting. The first is faster when there isn't a costly lookup to find the values being compared such as this case where the values are in an array and only needed to_i to compare them.
The *_by version performs a "Schwartzian transform" which basically remembers the values in the block as they're compared so the costly lookup only occurs once. (Many of Enumerable's methods have *_by versions.) These versions of the methods can improve the speed when you want to compare two values that are nested, perhaps in arrays of hashes of hashes, or objects within objects within objects.
Note: When comparing string versions of numbers it's important to convert to a numeric value when comparing. ASCII and strings order differently than numbers, hence the use of to_i.
I would like to generate all possible way of arranging of a certain number of elements number_of_elements. For now, I just want to print every possibility up to the possibility upto.
Edit: Say number_of_elements is 3, then I want all possible ways of arranging 0, 1 and 2. A number can appear 0 or many times, and order is important. So 0 != 00 != 01 != 10 != 11.
For example, all_combinations(3, 14) should print:
0
1
2
00
01
02
10
11
12
20
21
22
000 # updated. I originally put 100 here by mistake.
001
...
I tried this:
def all_combinations(number_of_elements, upto)
0.upto upto do |n|
puts n.to_s(number_of_elements)
end
end
all_combinations(3, 10)
My idea is to get all integers, convert them to base number_of_elements and interpret that number as the possibilities.
It almost works, except that I am missing some elements.
(This is the output I get with the code above) :
0
1
2
# 00 missing
# 01 missing
# 02 missing
10
11
12
20
21
22
# 0.. elements missing
100
101
...
Any idea or other simple method to get those?
Confer this question. The following is a slight modification of my answer there.
class Numeric
def sequence b
s, q = "", self
(q, r = (q - 1).divmod(b)) && s.prepend(r.to_s) until q.zero?
s
end
end
def foo(number_of_elements, upto)
1.upto upto do |n|
puts n.sequence(number_of_elements)
end
end
foo(3, 14)
Result:
0
1
2
00
01
02
10
11
12
20
21
22
000
001
You can do this using Array#repeated_permuation:
def all_combinations(nbr, upto)
(1..nbr).each_with_object([]) do |n, arr|
arr.concat(('0'...nbr.to_s).to_a
.repeated_permutation(n)
.to_a) if arr.size < upto
end.first(upto).each { |e| puts e.join }
end
all_combinations(3, 14)
0
1
2
00
01
02
10
11
12
20
21
22
000
001
If number_of_elements is large, this approach has the disadvantage that a substantial number of permutations may be added to the array arr, but not used. One alternative is to create an enumerator object which can be used to enumerate repeated permutations using Enumerator#next and Enumerator#peek, enumerating exactly upto values. I showed how to do that for permutation here and explained how it would be even easier for repeated_permutation.
Probably the cleanest way to attack this is--unfortunately, if you're not versed in recursion--with a recursive method.
You want to try every possible digit in every possible place, basically.
def all_combinations(s, number_of_elements, upto)
if number_of_elements < 1
puts s
return
end
0.upto upto - 1 do |n|
all_combinations(s + n.to_s, number_of_elements - 1, upto)
end
end
all_combinations("", 3, 10)
The premise is that, wherever you've gotten to in the process (s; imagine it's 12), you want to append all possible digits to it and continue. But, we don't want to go forever, and each digit we place gets us closer, so reduce number_of_elements; when number_of_elements is zero, we have nothing else to do, so it's time to print.
A couple of issues:
- upto doesn't know how big it is. If you call all_combinations("", 3, 500), you'll get badly-formed strings.
- As mentioned, if you're just learning programming, recursion might not be the best place to dive in.
- Likewise, if this is for homework and you haven't covered recursion, this would be a good sign that you're asking random people on the Internet for help, which may not result in an ideal grade.
With those caveats, though, I think this is the most straightforward approach. Everything else that comes to mind requires keeping track of positions and recent outputs manually, which...ick.
Here is a concise way of doing it using repeated_permutations:
def all_combinations(number_of_elements, upto)
elements = (0...number_of_elements).map(&:to_s)
combinations = (1..1.0/0).lazy.flat_map do |i|
elements.repeated_permutation(i).map do |permutation|
permutation.join
end
end
puts combinations.take(upto).to_a
end
all_combinations(3, 14)
0
1
2
00
01
02
10
11
12
20
21
22
000
001
Here's another way of doing this, using String#to_i and Fixnum#to_s, each with the argument base (which defaults to 10) set equal to the "number of elements":
def all_combinations(n_elements, upto)
s = '10'
upto.times.with_object([]) do |_,arr|
arr << s
candidate = (s.to_i(n_elements)+1).to_s(3)
(candidate = '1'+'0' * s.size) unless candidate[0] == '1'
s = candidate
end.map { |str| str[1..-1] }
end
all_combinations(3, 15)
#=> ["0", "1", "2",
# "00", "01", "02",
# "10", "11", "12",
# "20", "21", "22",
# "000", "001", "002"]
I have a for loop with an if elsif statement inside. On the first if, if the condition is met I want it to stop there and go on to the next iteration of the loop.
This is a very simplified version of what I am trying to do:
array = [1,2,3,4,"x"]
for i in 0..(array.count -1)
if array[i] == "x"
#start next for loop iteration without executing the elsif
elsif array[i] < 3
puts "YAY!"
end
end
What I am exactly trying to do is iterating through an array which all but one of the elements are integers but one of them is a string. On the string element, I need the loop (whatever kind is best) to skip the rest of the code and go to the next iteration of the loop. This is important because the second if statement uses an 'array_element < 11 condition' so if it runs that on the string element I get "comparison of String with 11 failed"
so I would want arr[x][3] this is what i tried but it gives me 8 8 8 8 instead of a single 8.
arr = [[1,2,3,"4"], [5,6,7,8], [9,10,11,12]]
arr.each{|x|
x.each {|i|
next if x[3].instance_of? String
if x[3] < 12 puts x[3]
end
}
}
Ok this works!! Thank you iAmRubuuu!!
arr = [1,2,3,"4"], [5,6,7,8], [9,10,11,12], [13,14,15,"16"], [17,18,19,20]]
arr.each_with_index{|x, i|
next if x.last.instance_of? String
if x.last < 21
puts x.last
end
}
give me the output
8
12
20
Don't use for in, use each.
(0..10).each do |i|
next if i == 5
if i == 10
puts "YAY!"
end
end
As per your edit, hope the below one you are looking for:
arr = [1, 2, 3, "11", 11]
arr.each do |x|
next if x.instance_of? String
puts "#{x} is #{x.class}"
end
Output:
1 is Fixnum
2 is Fixnum
3 is Fixnum
11 is Fixnum
EDIT
Code:
arr = [[1,2,3,"4"], [4,5,6,7], [8,9,10,11]]
arr.each{|x|
x.each{ |i|
next if i.instance_of? String
puts "#{i} is #{i.class}"
}
}
Output:
1 is Fixnum
2 is Fixnum
3 is Fixnum
4 is Fixnum
5 is Fixnum
6 is Fixnum
7 is Fixnum
8 is Fixnum
9 is Fixnum
10 is Fixnum
11 is Fixnum
V_1(from your first comment in my answer post)
arr = [[1,2,3,"4"], [4,5,6,7], [8,9,10,11]]
puts arr[1].last,arr.last.last
Output:
7
11
V_2(from your first comment in my answer post)
arr = [[1,2,3,"4"], [4,5,6,7], [8,9,10,11]]
arr.each_with_index{ |x,i|
next if i == 0
#p x,i
p "last element of inner array:#{x.last}"
}
Output:
"last element of inner array:7"
"last element of inner array:11"
I am trying to print all numbers between 1 and 50, using the following code:
[1..50].each{|n| puts n}
but the console print
[1..50]
I want to print something like this
1
2
3
4
...
50
Try the following code:
(1..50).each { |n| puts n }
The problem is that you're using [] delimiter instead of () one.
You can use [1..10] with a minor tweak:
[*1..10].each{ |i| p i }
outputs:
1
2
3
4
5
6
7
8
9
10
The * (AKA "splat") "explodes" the range into its components, which are then used to populate the array. It's similar to writing (1..10).to_a.
You can also do:
puts [*1..10]
to print the same thing.
So, try:
[*1..10].join(' ') # => "1 2 3 4 5 6 7 8 9 10"
or:
[*1..10] * ' ' # => "1 2 3 4 5 6 7 8 9 10"
To get the output you want.
The error here is that you are creating an Array object with a range as its only element.
> [1..10].size
=> 1
If you want to call methods like each on a range, you have to wrap the range in parentheses to avoid the method being called on the range's last element rather than on the range itself.
=> (1..10).each { |i| print i }
12345678910
Other ways to achieve the same:
(1..50).each { |n| print n }
1.up_to(50) { |n| print n }
50.times { |n| print n }
You can cast your range (in parentheses) to an array ([1 2 3 4 5 6... 48 49 50]) and join each item (e.g. with ' ' if you want all items in one line).
puts (1..50).to_a.join(' ')
# => 1 2 3 4 5 6 7 ... 48 49 50
I recently came upon the scary idea that Integer.count loops in Ruby start from 0 and go to n-1 while playing with the Facebook Engineering puzzlers. I did the dirty fix of adding one to the block variable in the beginning so that it would start at one instead.
Is there a prettier way?
Example:
10.times do |n|
n += 1
puts n
end #=> 012345789
Ruby supports a number of ways of counting and looping:
1.upto(10) do |i|
puts i
end
>> 1.upto(10) do |i|
> puts i
| end #=> 1
1
2
3
4
5
6
7
8
9
10
There's also step instead of upto which allows you to increment by a step value:
>> 1.step(10,2) { |i| puts i } #=> 1
1
3
5
7
9
You could use a range:
(1..10).each { |i| puts i }
Ranges give you full control over the starting and ending indexes (as long as you want to go from a lower value to a higher value).
Try
(1..10).each do |i|
# ... i goes from 1 to 10
end
instead. It is also easier to read when the value of i matters.
Old, but this might be something somebody's lookin for..
5.times.with_index(100){|i, idx| p i, idx};nil
#=>
0
100
1
101
2
102
3
103
4
104
There is of course the while-loop:
i = 1
while i<=10 do
print "#{i} "
i += 1
end
# Outputs: 1 2 3 4 5 6 7 8 9 10