How to add to an array with an if method - ruby

I have an array of numbers like so...
a= [28, 67, 20, 38, 4, 39, 14, 84, 20, 64, 7, 24, 17, 8, 7, 6, 15, 52, 4, 26]
I need to check if each of the numbers is greater than 30 and if so then I want to count that number and get a count of how many numbers are greater than 30. I have this but it is not working so far
def late_items
total_late = []
if a.map { |i| i > 30}
total_late << i
end
self.late_items = total_late.count
end

The count method can be passed a block to specify what kind of elements should be counted. Elements for which the block returns false or nil are ignored.
In your case, it would boil down to this:
array.count { |element| element > 30 }

You can use select to get all elements greater than 30.
a.select{|b| b > 30}.count
# => 6

Is is much simpler in Ruby:
a = [28, 67, 20, 38, 4, 39, 14, 84, 20, 64, 7, 24, 17, 8, 7, 6, 15, 52, 4, 26]
a.select{ |e| e > 30 }

It seems like you also want the index of each item that is over 30, if that is the case, this will work:
a= [28, 67, 20, 38, 4, 39, 14, 84, 20, 64, 7, 24, 17, 8, 7, 6, 15, 52, 4, 26]
count = 0
pos = []
a.each_with_index do |num, i|
if num > 30
count += 1
pos << i
end
end
puts count
print pos
#=> 6 [1,3,5,7,8,17]

You may also check the inject method. Within it you can easily get the sum of numbers greater than 30:
a.inject(0) { |sum, n| n > 30 ? sum += n : sum }
Or, if you have an array of numbers greater than 30, you can use reduce to summarize its items. Within your a variable it will look like:
a.select{ |n| n > 30 }.reduce(&:+)

Related

Generate numbers from n to m from a list

I'll start with an example; given n = 1 and m = 100 and a list [1, 2, 3]
generate all numbers with 1 digit and two digits and so on but they need to be less then 100 in this case.
Output:
- 1, 2, 3, 11, 12, 13, 21, 22, 23, 31, 32, 33
Then we stop because the next numbers will over 100, e.g:
- 111, 112, 113, 121, 122, 123, 131, 132, 133, 21..,. 22..., 23..., 31, 32, 33
As you noticed I am appending 1, 2, 3, 4 to a number created before, to do this I am using a recursive function, which is started in a for loop for each number in my list, and they it runs till the generated numbers are greater then my limit.
def x(str, finish, d, c)
return if d >= finish
[1, 2, 3, 4].each do |e|
x(str, end, d*c+e)
end
# do something if d >= str
end
This works fine if I need to start from 1, but if my starting number is a lot bigger, I still need to start to create this sequence.
Can somebody help me with a solution that will produce the same sequences, but from any starting point rather then 1, so if for example the starting point was 100 and end 200 the output will be:
111, 112, 113, 114, 121, 122, 123, 124, 131, 132, 132 [...]
A solution in any programming language would be nice, but please not builtin core libraries.
Code
def generate_em(minimum, maximum, list)
digits_min = minimum.to_s.size
digits_min += 1 if minimum > (list.max.to_s*digits_min).to_i
digits_max = maximum.to_s.size
digits_max -= 1 if maximum < (list.min.to_s*digits_max).to_i
(digits_min..digits_max).each_with_object([]) { |n,arr|
arr.concat(list.repeated_permutation(n).to_a.map { |a| a.join.to_i }) }.
uniq.
select { |n| (minimum..maximum).cover?(n) }
end
Examples
#1
minimum = 1
maximum = 100
list = [1, 2, 3]
generate_em(minimum, maximum, list)
#=> [1, 2, 3, 11, 12, 13, 21, 22, 23, 31, 32, 33]
#2
minimum = 78
maximum = 3332
list = [3, 4, 5, 6, 7]
generate_em(minimum, maximum, list)
#=> [333, 334, 335, 336, 337, 343, 344, 345, 346, 347, 353, 354, 355, 356,
# 357, 363, 364, 365, 366, 367, 373, 374, 375, 376, 377, 433, 434, 435,
# 436, 437, 443, 444, 445, 446, 447, 453, 454, 455, 456, 457, 463, 464,
# 465, 466, 467, 473, 474, 475, 476, 477, 533, 534, 535, 536, 537, 543,
# 544, 545, 546, 547, 553, 554, 555, 556, 557, 563, 564, 565, 566, 567,
# 573, 574, 575, 576, 577, 633, 634, 635, 636, 637, 643, 644, 645, 646,
# 647, 653, 654, 655, 656, 657, 663, 664, 665, 666, 667, 673, 674, 675,
# 676, 677, 733, 734, 735, 736, 737, 743, 744, 745, 746, 747, 753, 754,
# 755, 756, 757, 763, 764, 765, 766, 767, 773, 774, 775, 776, 777]
#3
minimum = 0
maximum = 100
list = [0, 1, 2]
generate_em(minimum, maximum, list)
#=> [0, 1, 2, 10, 11, 12, 20, 21, 22, 100]
Explanation
Example #1
The steps for the first example above are as follows.
digits_min = minimum.to_s.size
#=> 1
Increase digits_min by one if mimimum is larger than the largest digits_min digits from list.
digits_min += 1 if minimum > (list.max.to_s*digits_min).to_i
digits_min
#=> 1
digits_max = maximum.to_s.size
#=> 3
Decrease digits_max by one if maximum is smaller than the smallest digits_max digits from list.
digits_max -= 1 if maximum < (list.min.to_s*digits_max).to_i
digits_max
#=> 2
We improve efficiency by having reduced digits_max from 3 to 2
c = digits_min..digits_max
#=> 1..2
d = c.each_with_object([])
#=> #<Enumerator: 1..2:each_with_object([])>
We can see the elements that will be generated by this enumerator by invoking Enumerable#entries (or Enumerable#to_a) on it.
d.entries
#=> [[1, []], [2, []]]
n, arr = d.next
#=> [1, []]
n #=> 1
arr
#=> []
e = list.permutation(n)
#=> #<Enumerator: [1, 2, 3]:permutation(2)>
f = e.to_a
#=> [[1], [2], [3]]
arr.concat f
#=> [[1], [2], [3]]
n, arr = d.next
#=> [2, [[1], [2], [3]]]
n #=> 2
arr
#=> [[1], [2], [3]]
e = list.permutation(n)
#=> #<Enumerator: [1, 2, 3]:permutation(2)>
f = e.to_a
#=> [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
arr.concat f
#=> [[1], [2], [3], [1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
arr is returned by each_with_object's block.
g = arr.map { |a| a.join.to_i }
#=> [1, 2, 3, 12, 13, 21, 23, 31, 32]
h = g.uniq
#=> [1, 2, 3, 12, 13, 21, 23, 31, 32]
h.select { |n| (minimum..maximum).cover?(n) }
#=> [1, 2, 3, 12, 13, 21, 23, 31, 32]
Example #2
In the second example no two-digit combinations are generated because
78 > (list.max.to_s*2).to_i
#=> 78 > 77 => true
and no four-digit combinations are generated because
3332 < (list.min.to_s*4).to_i
#=> 3332 < 3333 => true
Example #3
Without uniq, the method would have returned duplicate values:
[0, 1, 2, 0, 1, 2, 10, 11, 12, 20, 21, 22, 0, 1, 2, 10, 11, 12, 20, 21, 22, 100]
Since you wrote your example code in Ruby, you could use repeated_permutation :
def possible_numbers(arr, min, max)
min_digits = min.to_s.size
max_digits = max.to_s.size
(min_digits..max_digits).flat_map do |i|
arr.repeated_permutation(i)
.map { |digits| digits.join.to_i }
.select { |number| number >= min && number <= max }
.uniq
end
end
p possible_numbers([1, 2, 3], 100, 200)
# => [111, 112, 113, 121, 122, 123, 131, 132, 133]
So, this takes an input of the digits provided, makes all the digit combinations repeatedly until it reaches your max. You'll want to adjust them to include recovery and saves in the event non-integers are entered or if it's otherwise impossible to hit the max for some reason - but this is a solid framework.
digits = [1,2,3]
max = 100
def possible_numbers(arr, max)
loop do
arr.product(arr).each do |combo|
return arr.uniq if combo.join("").to_i > max
arr << combo.join("").to_i
end
end
end
possible_numbers(digits, max)
Output:
=> [1, 2, 3, 11, 12, 13, 21, 22, 23, 31, 32, 33]
You can proceed from "right" (least significant digit) to "left" (most significant digit), keeping track of two values:
min, the least valid integer that has the same number of digits as what you've processed so far. So, for example, if you've processed a trailing 27, then the least valid two-digit integer is 11.
max, the least valid integer that has the same number of digits as what you've processed so far and is greater than or equal to what you've processed so far. So, for example, if you've processed a trailing 27, then the least valid two-digit integer greater than or equal to 27 is 31.
Note that max won't always exist. For example, there's no valid two-digit integer greater than or equal to 70.
The reason you need min is that if you encounter a digit that's not in your list of allowed digits, then the new max will incorporate the previous min instead of the previous max. (For example, the least valid two-digit integer greater than or equal to 02 is 11, not 12.)
At the end, you return max, if it exists; otherwise, you return min, but prepending the least digit from your list.
For example, if this.allowedDigits is a collection of allowed digits, then we can write (in Java):
private Integer getAllowedDigitGreaterThanOrEqualTo(final int digit) {
for (int result = digit; result < 10; ++result) {
if (this.allowedDigits.contains(result)) {
return result;
}
}
// digit is bigger than anything in the list:
return null;
}
private int getAllowedNumberGreaterThanOrEqualTo(int n) {
int minResult = 0;
Integer maxResult = 0;
int powerOfTen = 1;
while (n > 0) {
final int digit = n % 10;
n /= 10;
minResult = getAllowedDigitGreaterThanOrEqualTo(0) * powerOfTen + minResult;
if (maxResult != null && this.allowedDigits.contains(digit)) {
maxResult = digit * powerOfTen + maxResult;
} else {
final Integer newDigit = getAllowedDigitGreaterThanOrEqualTo(digit + 1);
if (newDigit == null) {
maxResult = null;
} else {
maxResult = newDigit * powerOfTen + minResult;
}
}
powerOfTen *= 10;
}
if (maxResult == null) {
return getAllowedDigitGreaterThanOrEqualTo(1) * powerOfTen + minResult;
} else {
return maxResult;
}
}

Is there a way to specify a multi-step in Ruby?

I'm working with some lazy iteration, and would like to be able to specify a multiple step for this iteration. This means that I want the step to alternate between a and b. So, if I had this as a range (not lazy just for simplification)
(1..20).step(2, 4)
I would want my resulting range to be
1 # + 2 =
3 # + 4 =
7 # + 2 =
9 # + 4 =
13 # + 2 =
15 # + 4 =
19 # + 2 = 21 (out of range, STOP ITERATION)
However, I cannot figure out a way to do this. Is this at all possible in Ruby?
You could use a combination of cycle and Enumerator :
class Range
def multi_step(*steps)
a = min
Enumerator.new do |yielder|
steps.cycle do |step|
yielder << a
a += step
break if a > max
end
end
end
end
p (1..20).multi_step(2, 4).to_a
#=> [1, 3, 7, 9, 13, 15, 19]
Note that the first element is 1, because the first element of (1..20).step(2) is also 1.
It takes exclude_end? into account :
p (1...19).multi_step(2, 4).to_a
#=> [1, 3, 7, 9, 13, 15]
And can be lazy :
p (0..2).multi_step(1,-1).first(20)
#=> [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
p (0..Float::INFINITY).multi_step(*(1..100).to_a).lazy.map{|x| x*2}.first(20)
#=> [0, 2, 6, 12, 20, 30, 42, 56, 72, 90, 110, 132, 156, 182, 210, 240, 272, 306, 342, 380]
Here's a variant of FizzBuzz, which generates all the multiples of 3 or 5 but not 15 :
p (3..50).multi_step(2,1,3,1,2,6).to_a
#=> [3, 5, 6, 9, 10, 12, 18, 20, 21, 24, 25, 27, 33, 35, 36, 39, 40, 42, 48, 50]
Ruby doesn't have a built-in method for stepping with multiple values. However, if you don't actually need a lazy method, you can use Enumerable#cycle with an accumulator. For example:
range = 1..20
accum = range.min
[2, 4].cycle(range.max) { |step| accum += step; puts accum }
Alternatively, you could construct your own lazy enumerator with Enumerator::Lazy. That seems like overkill for the given example, but may be useful if you have an extremely large Range object.

Make a square multiplication table in Ruby

I got this question in an interview and got almost all the way to the answer but got stuck on the last part. If I want to get the multiplication table for 5, for instance, I want to get the output to be formatted like so:
1, 2, 3, 4, 5
2, 4, 6, 8, 10
3, 6, 9, 12, 15
4, 8, 12, 16, 20
5, 10, 15, 20, 25
My answer to this is:
def make_table(n)
s = ""
1.upto(n).each do |i|
1.upto(n).each do |j|
s += (i*j).to_s
end
s += "\n"
end
p s
end
But the output for make_table(5) is:
"12345\n246810\n3691215\n48121620\n510152025\n"
I've tried variations with array but I'm getting similar output.
What am I missing or how should I think about the last part of the problem?
You can use map and join to get a String in one line :
n = 5
puts (1..n).map { |x| (1..n).map { |y| x * y }.join(', ') }.join("\n")
It iterates over rows (x=1, x=2, ...). For each row, it iterates over cells (y=1, y=2, ...) and calculates x*y. It joins every cells in a row with ,, and joins every rows in the table with a newline :
1, 2, 3, 4, 5
2, 4, 6, 8, 10
3, 6, 9, 12, 15
4, 8, 12, 16, 20
5, 10, 15, 20, 25
If you want to keep the commas aligned, you can use rjust :
puts (1..n).map { |x| (1..n).map { |y| (x * y).to_s.rjust(3) }.join(',') }.join("\n")
It outputs :
1, 2, 3, 4, 5
2, 4, 6, 8, 10
3, 6, 9, 12, 15
4, 8, 12, 16, 20
5, 10, 15, 20, 25
You could even go fancy and calculate the width of n**2 before aligning commas :
n = 11
width = Math.log10(n**2).ceil + 1
puts (1..n).map { |x| (1..n).map { |y| (x * y).to_s.rjust(width) }.join(',') }.join("\n")
It outputs :
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22
3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33
4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44
5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55
6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66
7, 14, 21, 28, 35, 42, 49, 56, 63, 70, 77
8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88
9, 18, 27, 36, 45, 54, 63, 72, 81, 90, 99
10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110
11, 22, 33, 44, 55, 66, 77, 88, 99, 110, 121
Without spaces between the figures, the result is indeed unreadable. Have a look at the % operator, which formats strings and numbers. Instead of
s += (i*j).to_s
you could write
s += '%3d' % (i*j)
If you really want to get the output formatted in the way you explained in your posting (which I don't find that much readable), you could do a
s += "#{i*j}, "
This leaves you with two extra characters at the end of the line, which you have to remove. An alternative would be to use an array. Instead of the inner loop, you would have then something like
s += 1.upto(n).to_a.map {|j| i*j}.join(', ') + "\n"
You don't need to construct a string if you're only interested in printing the table and not returning the table(as a string).
(1..n).each do |a|
(1..n-1).each { |b| print "#{a * b}, " }
puts a * n
end
This is how I'd do it.
require 'matrix'
n = 5
puts Matrix.build(n) { |i,j| (i+1)*(j+1) }.to_a.map { |row| row.join(', ') }
1, 2, 3, 4, 5
2, 4, 6, 8, 10
3, 6, 9, 12, 15
4, 8, 12, 16, 20
5, 10, 15, 20, 25
See Matrix::build.
You can make it much shorter but here's my version.
range = Array(1..12)
range.each do |element|
range.map { |item| print "#{element * item} " } && puts
end

Ruby Array#include method not working as intended

Why is the include method not working well? The original question is from the Euler project, Problem 23. I couldn't figure out how to debug it.
My code:
def proper_divisors(n)
(1...n).select {|x| n % x == 0 }.inject(0){|x,y| x + y}
end
def abundant?(n)
(1...n).select {|x| n % x == 0 }.inject(0){|x,y| x + y} > n
end
def non_abundant_sums
s = 0
arr = (12..40).select { |n| n if abundant?(n) }
p arr
(1..40).each do |x|
p x unless arr.include?(proper_divisors(x) - x)
s = s + x unless arr.include?(proper_divisors(x) - x)
end
s
end
p non_abundant_sums
Using p x unless arr.include?(proper_divisors(x) - x) in the above code prints 1 through 40:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40
What I want it to print is 1 through 39:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 31, 33, 34, 35, 37, 39
A solution based on the original methods from the example.
In file problem_23.rb:
def proper_divisors(n)
(1...n).select {|x| n % x == 0 }.inject(0) {|x,y| x + y}
end
def abundant?(n)
proper_divisors(n) > n
end
def non_abundant_sum(low_n, high_n, debug=false)
puts "get all the abundant numbers within range #{low_n} to #{high_n}" if debug
arr = (low_n..high_n).select {|n| n if abundant?(n)}
puts arr.sort.inspect if debug
# http://ruby-doc.org/core-2.1.2/Array.html#method-i-repeated_combination
puts "all combinations of two abundant numbers" if debug
arr = arr.repeated_combination(2).to_a
puts arr.inspect if debug
puts "all unique sums of two abundant number combinations" if debug
arr = arr.map {|x| x[0] + x[1]}.uniq
puts arr.sort.inspect if debug
puts "only select numbers within range" if debug
arr = arr.select {|x| low_n <= x && x <= high_n}
puts arr.inspect if debug
puts "all positive integers within range" if debug
arr2 = (low_n..high_n).map {|i| i}
puts arr2.inspect if debug
puts "all positive integers less all the sums of two abundant numbers" if debug
arr = arr2 - arr
puts arr.inspect if debug
puts "sum of all the positive integers which cannot be written as the sum of two abundant numbers within range #{low_n} to #{high_n}" if debug
arr.inject(0) {|sum,n| sum + n}
end
puts non_abundant_sum(12, 40, true)
Running the code:
$ ruby problem_23.rb
get all the abundant numbers within range 12 to 40
[12, 18, 20, 24, 30, 36, 40]
all combinations of two abundant numbers
[[12, 12], [12, 18], [12, 20], [12, 24], [12, 30], [12, 36], [12, 40], [18, 18], [18, 20], [18, 24], [18, 30], [18, 36], [18, 40], [20, 20], [20, 24], [20, 30], [20, 36], [20, 40], [24, 24], [24, 30], [24, 36], [24, 40], [30, 30], [30, 36], [30, 40], [36, 36], [36, 40], [40, 40]]
all unique sums of two abundant number combinations
[24, 30, 32, 36, 38, 40, 42, 44, 48, 50, 52, 54, 56, 58, 60, 64, 66, 70, 72, 76, 80]
only select numbers within range
[24, 30, 32, 36, 38, 40]
all positive integers within range
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
all positive integers less all the sums of two abundant numbers
[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 26, 27, 28, 29, 31, 33, 34, 35, 37, 39]
sum of all the positive integers which cannot be written as the sum of two abundant numbers within range 12 to 40
554

How do I split arrays using a while loop?

I want to write a program that splits an array into two arrays, where any element in one array is smaller than any element in the other array.
The input that I have is:
a = [6, 45, 23, 65, 17, 48, 97, 32, 18, 9, 88]
And I'd like output like this:
[6, 23, 17, 18 , 9] < [45, 65, 48, 97, 32, 88]
I've tried:
i = 0
max = 0
while i < a.size
if a[i] > max
max = a[i]
end
i+=1
end
puts "this is the larger array: " + max.to_s
Which is completely off. As I am new to this, any help is appreciated.
small, large = a.sort!.shift(a.size/2) ,a
p small, large
#=> [6, 9, 17, 18, 23]
#=> [32, 45, 48, 65, 88, 97]
Try this:
newarray = a.sort.each_slice((a.size/2.0).round).to_a
It will give you an array containing your split array:
newarray = [[6,9,17,18,23,32],[45,48,65,88,97]]
In this case, if you have an odd number of elements in your array, the first array returned will always have the extra element. You can also save the arrays separately if you would like, but this way you can call each of the halves with newarray[0] and newarray[1]. If you want to split them simply add:
b = newarray[0]
c = newarray[1]
Don't use a while loop - sort the array and then split it in two
a.sort
a.in_groups_of( a.size/2)
a.sort.each_slice( a.size/2) probably does the trick without rails.
a = [6, 45, 23, 65, 17, 48, 97, 32, 18, 9, 88]
a = a.sort
print a.shift(a.count/2), " < " , a
#=> [6, 9, 17, 18, 23] < [32, 45, 48, 65, 88, 97]
Another variation
a = [6, 45, 23, 65, 17, 48, 97, 32, 18, 9, 88]
a = a.sort
print a.values_at(0..a.count/2), " < ", a.values_at((a.count/2)+1 .. -1)
#=> [6, 9, 17, 18, 23] < [32, 45, 48, 65, 88, 97]
Assuming you want to preserve order, as in your example:
def split_it(a,n)
f = a.select {|e| e <= n}
[f, a-f]
end
a = [6, 45, 23, 65, 17, 48, 97, 32, 18, 9, 88]
f, l = split_it(a,23)
puts "#{f} < #{l}" # => [6, 23, 17, 18, 9] < [45, 65, 48, 97, 32, 88]
If you want to preserve order and have the first subarray contain nbr elements, add this:
def split_nbr(a, nbr)
n = 1
loop do
return [] if n > a.max
b = split_it(a,n)
return b if b.first.size == nbr
n += 1
end
end
f, l = split_nbr(a,3)
puts "#{f} < #{l}" # => [6, 17, 9] < [45, 23, 65, 48, 97, 32, 18, 88]

Resources