Codewars exercise "Count by X" not working - ruby

I'm tryng to do this exercise:
Create a function with two arguments that will return a list of length
(n) with multiples of (x).
Assume both the given number and the number of times to count will be
positive numbers greater than 0.
Return the results as an array (or list in Python, Haskell or Elixir).
Examples:
count_by(1,10) #should return [1,2,3,4,5,6,7,8,9,10]
count_by(2,5) #should return [2,4,6,8,10]
Quite easy, nothing to say. BUT I really do not understand why my code is not working.
PLease DO NOT GIVE ME NEW CODE OR SOLUTION, I JUST WANT TO UNDERSTAND WHY MINE DOESN'T WORK.
My solution:
def count_by(x, n)
arrays = []
arrays.push(x)
valore_x = x
unless arrays.count == n
arrays.push( x + valore_x)
x += valore_x
end
return arrays
end
count_by(3, 5)
ERROR MESSAGE =
Expected: [1, 2, 3, 4, 5], instead got: [1, 2]
✘ Expected: [2, 4, 6, 8, 10], instead got: [2, 4]
✘ Expected: [3, 6, 9, 12, 15], instead got: [3, 6]
✘ Expected: [50, 100, 150, 200, 250], instead got: [50, 100]
✘ Expected: [100, 200, 300, 400, 500], instead got: [100, 200].
So looks like that my code do not put all the numbers. Thanks.

Now you have answer on your question, so I just recommend one more variant of solution, I think it's more ruby-way :)
def count_by(x, y)
y.times.with_object([]) do |i, result|
result << x*(i+1)
end
end

Change
unless arrays.count == n
to
until arrays.count == n
unless is not a loop. It's just like an if, but the code is executed if the condition is false.
until is just like while, but the code is executed while the condition is false.

Array::new can be used here.
def count_by(x, n)
Array.new(n) { |i| x*(i+1) }
end
count_by(1,5) #=> [1, 2, 3, 4, 5]
count_by(2,5) #=> [2, 4, 6, 8, 10]
count_by(3,5) #=> [3, 6, 9, 12, 15]
count_by(50,5) #=> [50, 100, 150, 200, 250]
count_by(100,5) #=> [100, 200, 300, 400, 500]
count_by(0,5) #=> [0, 0, 0, 0, 0]

Just a few other ways to achieve the same result. Using Numeric#step:
x.step(by: x, to: x*y).entries
shorter but less readable:
x.step(x*y, x).entries
or using a range with Range#step:
(x..x*y).step(x).entries
In each of the examples entries can be replaced with to_a

Related

how do i reverse individual (and specific) columns in a 2d array (RUBY)

RUBY the goal is to get the max value from each of the four zones and get their sum.
UPDATE I came up with a solution, I'm sorry about the mixup. It turned out that the matrix is a 2n x 2n matrix so it could have been greater or smaller than 4x4 in fact it. The solution i wrote below worked on all of the test cases. Here is a link to the problem
I tried doing matrix.transpose then I tried reversing the specific array, that didn't work for all edge cases.
Here is the code for that
def flippingMatrix(matrix)
2.times do
matrix = matrix.transpose
matrix = matrix.map do |array|
if (array[-1] == array.max) || (array[-2] == array.max)
array.reverse
else
array
end
end
end
return matrix[0][0] + matrix[0][1] + matrix[1][0] + matrix[1][1]
end
I gave up and tried the below, which in my mind works, it also works for most edge cases but not all.
But i'm getting an error (undefined method `[]' for nil:NilClass (NoMethodError))
keep in mind when I print the results or spot_1, spot_2, spot_3, or spot_4 I get the correct answer. does anyone have an idea why this is happening?
Here is a matrix that FAILED
[
[517, 37, 380, 3727],
[3049, 1181, 2690, 1587],
[3227, 3500, 2665, 383],
[4041, 2013, 384, 965]
]
**expected output: 12,881 (this fails)**
**because 4041 + 2013 + 3227 + 3500 = 12,881**
Here is a matrix that PASSED
[
[112, 42, 83, 119],
[56, 125, 56, 49],
[15, 78, 101, 43],
[62, 98, 114, 108],
]
**expected output: 414 (this passes)**
Here is the code
def flippingMatrix(matrix)
# Write your code here
spot_1 = [matrix[0][0] , matrix[0][3] , matrix[3][0] , matrix[3][3]].max
spot_2 = [matrix[0][1] , matrix[0][2] , matrix[3][1] , matrix[3][2]].max
spot_3 = [matrix[1][0] , matrix[1][3] , matrix[2][0] , matrix[2][3]].max
spot_4 = [matrix[1][1] , matrix[1][2] , matrix[2][1] , matrix[2][2]].max
return (spot_1 + spot_2 + spot_3 + spot_4)
end
I will answer your question and at the same time suggest two other ways to obtain the desired sum.
Suppose
arr = [
[ 1, 30, 40, 2],
[300, 4000, 1000, 200],
[400, 3000, 2000, 100],
[ 4, 10, 20, 3]
]
First solution
We see that the desired return value is 4444. This corresponds to
A B B A
C D D C
C D D C
A B B A
First create three helper methods.
Compute the largest value among the four inner elements
def mx(arr)
[arr[1][1], arr[1][2], arr[2][1], arr[2][2]].max
end
mx(arr)
#=> 4000
This is the largest of the "D" values.
Reverse the first two and last two rows
def row_flip(arr)
[arr[1], arr[0], arr[3], arr[2]]
end
row_flip(arr)
#=> [[300, 4000, 1000, 200],
# [ 1, 30, 40, 2],
# [ 4, 10, 20, 3],
# [400, 3000, 2000, 100]]
This allows us to use the method mx to obtain the largest of the "B" values.
Reverse the first two and last two columns
def column_flip(arr)
row_flip(arr.transpose).transpose
end
column_flip(arr)
#= [[ 30, 1, 2, 40],
# [4000, 300, 200, 1000],
# [3000, 400, 100, 2000],
# [ 10, 4, 3, 20]]
This allows us to use the method mx to obtain the largest of the "C" values.
Lastly, the maximum of the "A" values can be computed as follows.
t = row_flip(column_flip(arr))
#=> [[4000, 300, 200, 1000],
# [ 30, 1, 2, 40],
# [ 10, 4, 3, 20],
# [3000, 400, 100, 2000]]
mx(column_flip(t))
#=> 4
The sum of the maximum values may therefore be computed as follows.
def sum_max(arr)
t = column_flip(arr)
mx(arr) + mx(row_flip(arr)) + mx(t) + mx(row_flip(t))
end
sum_max(arr)
#=> 4444
Second solution
Another way is the following:
[0, 1].product([0, 1]).sum do |i, j|
[arr[i][j], arr[i][-j-1], arr[-i-1][j], arr[-i-1][-j-1]].max
end
#=> 4444
To see how this works let me break this into two statements add a puts statement. Note that, for each of the groups A, B, C and D, the block variables i and j are the row and column indices of the top-left element of the group.
top_left_indices = [0, 1].product([0, 1])
#=> [[0, 0], [0, 1], [1, 0], [1, 1]]
top_left_indices.sum do |i, j|
a = [arr[i][j], arr[i][-j-1], arr[-i-1][j], arr[-i-1][-j-1]]
puts a
a.max
end
#=> 4444
The prints the following.
[1, 2, 4, 3]
[30, 40, 10, 20]
[300, 200, 400, 100]
[4000, 1000, 3000, 2000]
ahhh I came up with an answer that answers all edge cases. I originally saw something like this in Javascript and kind of turned it into Ruby. Apparently some of the hidden edge cases (that were hidden) weren't all 4 by 4 some were smaller and some larger, that was the cause of the nil error.
Here is the solution:
def flippingMatrix(matrix)
total = []
(0...(matrix.length/2)).each do |idx1|
(0...(matrix.length/2)).each do |idx2|
total << [matrix[idx1][idx2],
matrix[(matrix.length - 1)-idx1][idx2],
matrix[idx1][(matrix.length - 1)-idx2],
matrix[(matrix.length - 1)-idx1][(matrix.length - 1)-idx2]].max
end
end
total.sum
end
Thank you all for your support! I hope this helps someone in the near future.

adding array elements using recursion

I need to create a recursive function that adds the numbers of any given array, then removes the first element, then adds the array and do this until the array only has element left.
my function does this but at the moment I can only see the addition by putting a puts statement but also need the results as the return value like this =>[20,20,19,16,10] and dont know how to go about this as its putting the results separately. Thanks for your help.
The function needs to do this recursively:
I this is my code:
def parts_sums(ls)
results_arr=[]
if( ls.length === 1)
return ls
end
p results =ls.sum
parts_sums(ls.drop(1))
p results_arr << results
end
parts_sums([0, 1, 3, 6, 10])
# ls = [0, 1, 3, 6, 10].sum =>20
# ls = [1, 3, 6, 10].sum => 20
# ls = [3, 6, 10].sum =>19
# ls = [6, 10].sum =>16
# ls = [10]=>10
You can define a method like this, which is verbose but clear (I think):
def parts_sums(ary, res = [])
res << [ary.dup, ary.sum]
if ary.size > 1
ary.shift
parts_sums(ary, res)
else
return res
end
end
So, when you call on your array, you get this result:
ary = [0, 1, 3, 6, 10]
parts_sums(ary)
#=> [[[0, 1, 3, 6, 10], 20], [[1, 3, 6, 10], 20], [[3, 6, 10], 19], [[6, 10], 16], [[10], 10]]
Call parts_sums(ary.dup) if you want to preserve the original array.
Which can be rewritten in this shortest way:
def parts_sums_2(ary, res = [])
return res unless ary.any?
res << [ary, ary.sum]
parts_sums_2(ary[1..-1], res)
end
def parts_sums(ls)
ls.length == 1 ? ls : ([ls.sum] + parts_sums(ls[1..-1]))
end
puts parts_sums([0, 1, 3, 6, 10]).to_s

List the factors of a non-prime number

My goal is to display if a number is prime, and if it is not, list all of its factors. If I input 6, the program should return:
6 is not a prime number => 2, 3
Here is what I have so far:
puts "Enter a number: "
num = gets
num = num.to_i
def prime(num)
is_prime = true
for i in 2..num-1
if num % i == 0
is_prime = false
end
end
if is_prime
puts "#{num} is prime!"
else
puts "#{num} is not prime!"
end
end
prime(num)
I tried making a while loop for this but I can't seem to make it work. I'm not sure if I am using the num%i==0 formula correctly. Any help would be appreciated.
If permitted to do so, use the Standard Library class Prime.
require 'prime'
def is_prime? n
n.prime? ? n : Prime.prime_division(n)
end
p is_prime? 6 #=> [[2, 1], [3, 1]]
p is_prime? 11 #=> 11
p is_prime? 100 #=> [[2, 2], [5, 2]]
Homework hint 1)
You need to change the following things in order to get all the factors:
do not stop as soon as you find one factor
(which your prime-finder code inefficiently does not do anyway...)
print each factor you find
If you also need the correct exponent you further need to
check for each found factor whether it is still a factor after dividing by it,
this needs to be done in a loop
Homework hint 2)
In order to get a specific desired output, print the decoration (e.g. "," and newlines) explicitly when it is needed.
Printing the statement first and only once can be done by using a flag for "already printed" and checking it before printing the statement in the loop.
(I assume that this is a homework question and am therefor intentionally not giving a complete solution, according to the compromise desccribed here How do I ask and answer homework questions?
Thank you for not minding my assumption, or so I gather from your accepting my answer. In case it is not about homework I assume that you appreciated the help and the way of helping, in spite of my mistake.)
require 'prime'
def factors(n)
first, *rest =
Prime.prime_division(n).map { |n,power| [n].product((0..power).to_a) }
first.product(*rest).map { |a| a.reduce(1) { |t,(n,power)| t * n**power } }
end
Let's use this method to compute the factors of 1500.
factors 1500
#=> [ 1, 5, 25, 125,
# 3, 15, 75, 375,
# 2, 10, 50, 250,
# 6, 30, 150, 750,
# 4, 20, 100, 500,
# 12, 60, 300, 1500]
Note that
Prime.prime_division(1500)
#=> [[2, 2], [3, 1], [5, 3]]
and
Prime.prime_division(500).map { |n,power| [n].product((0..power).to_a) }
#=> [[[2, 0], [2, 1], [2, 2]], [[5, 0], [5, 1], [5, 2], [5, 3]]]
Moreover, factors(n).size equals 2 if and only if n is prime. For example,
factors(37)
#=> [1, 37]
Prime.prime?(37)
#=> true
See Prime::prime_division.

Algorithm: Factor Combinations

I'm working on the following algorithm from Leetcode:
Numbers can be regarded as product of its factors. For example,
8 = 2 x 2 x 2;
= 2 x 4.
Write a function that takes an integer n and return all possible combinations of its factors.
Note:
You may assume that n is always positive.
Factors should be greater than 1 and less than n.
Examples:
input: 1
output:
[]
input: 37
output:
[]
input: 12
output:
[
[2, 6],
[2, 2, 3],
[3, 4]
]
input: 32
output:
[
[2, 16],
[2, 2, 8],
[2, 2, 2, 4],
[2, 2, 2, 2, 2],
[2, 4, 4],
[4, 8]
]
Here's the code that I have thus far:
def get_factors(n)
factors = []
(2...n).each do |candidate|
if n % candidate == 0
factors << [candidate, (n/candidate)]
get_factors(n/candidate).each do |factor_set|
factors << [candidate] + factor_set
end
end
end
factors
end
This code works really well, but doesn't handle duplicates (e.g [3, 2, 2] will be inserted along with [2, 2, 3]). I tried using a Set with the following code,
def get_factors(n)
seen = Set.new
factors = []
(2...n).each do |candidate|
if n % candidate == 0 && !seen.include?(candidate)
factors << [candidate, (n/candidate)]
get_factors(n/candidate).each do |factor_set|
factors << [candidate] + factor_set
end
end
seen << (n/candidate)
end
factors
end
but that only works to solve some test cases and not others. I'm not sure how to go about ensuring no duplicates in an efficient way? The really inefficient way is to generate some sort of hash value for each array depending on it's elements (and not dependent on order), and while this would work, there definitely should be a better way. Any ideas?
I think always going forward is a good policy (i.e when checking, say, with 5, do not check with 2, 3, 4 etc). That way, searching for duplicates can be eliminated.
Since the algorithm already uses a lot of time, I don't see a problem sorting each answer and removing duplicates. This requires no proof to ensure it works, which the answer provided by mac does.
Code
require 'prime'
def get_factors(n)
primes, nbr = Prime.prime_division(n).transpose
powers = nbr.map { |m| (0..m).to_a }
powers.shift.
product(*powers).
map { |pows| primes.zip(pows).reduce(1) { |t,(pr,po)| t * (pr**po) } }.
sort
end
The array returned includes 1 and n (which are factors of n). If those values should be excluded, replace .sort with .sort - [1, n].
Examples
get_factors(24)
#=> [1, 2, 3, 4, 6, 8, 12, 24]
get_factors(64)
#=> [1, 2, 4, 8, 16, 32, 64]
get_factors(90)
#=> [1, 2, 3, 5, 6, 9, 10, 15, 18, 30, 45, 90]
Explanation
Consider
n = 60
The steps are as follows.
a = Prime.prime_division(30)
#=> [[2, 2], [3, 1], [5, 1]]
Ergo, the primes of 30 are 2, 3 and 5, and
60 = 2**2 * 3**1 * 5**1
See Prime::prime_division. Continuing,
primes, nbr = a.transpose
#=> [[2, 3, 5], [2, 1, 1]]
primes
#=> [2, 3, 5]
nbr
#=> [2, 1, 1]
powers = nbr.map { |m| (0..m).to_a }
#=> [[0, 1, 2], [0, 1], [0, 1]]
This means that each factor will be the product of 0, 1 or 2 2's, 0 or 1 3's and 0 or 1 5's.
b = powers.shift
#=> [0, 1, 2]
powers
#=> [[0, 1], [0, 1]]
c = b.product(*powers)
#=> [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1],
# [1, 1, 0], [1, 1, 1], [2, 0, 0], [2, 0, 1], [2, 1, 0], [2, 1, 1]]
d = c.map { |pows| primes.zip(pows).reduce(1) { |t,(pr,po)| t * (pr**po) } }
#=> [1, 5, 3, 15, 2, 10, 6, 30, 4, 20, 12, 60]
d.sort
#=> [1, 5, 3, 15, 2, 10, 6, 30, 4, 20, 12, 60]
Consider now the calculation of d. The 10th element of c that is passed to the block is [2, 0, 1]. The block calculation for that element is as follows.
pows = [2, 0, 1]
e = primes.zip(pows)
#=> [[2, 2], [3, 0], [5, 1]]
e.reduce(1) { |t,(pr,po)| t * (pr**po) }
#=> 20
The reduce calculation is equivalent to
2**2 * 3**0 * 5**1
#=> 4 * 1 * 5 => 20
The calculations for the other values of c passed to the block are similar.
A simple way is to replace the last line of your method with
factors.map(&:sort).uniq
which sorts all the subarrays and then eliminates duplicates.

Every Other 2 Items in Array

I need a ruby formula to create an array of integers. The array must be every other 2 numbers as follows.
[2, 3, 6, 7, 10, 11, 14, 15, 18, 19...]
I have read a lot about how I can do every other number or multiples, but I am not sure of the best way to achieve what I need.
Here's an approach that works on any array.
def every_other_two arr
arr.select.with_index do |_, idx|
idx % 4 > 1
end
end
every_other_two((0...20).to_a) # => [2, 3, 6, 7, 10, 11, 14, 15, 18, 19]
# it works on any array
every_other_two %w{one two three four five six} # => ["three", "four"]
array = []
#Change 100000 to whatever is your upper limit
100000.times do |i|
array << i if i%4 > 1
end
This code works for any start number to any end limit
i = 3
j = 19
x =[]
(i...j).each do |y|
x << y if (y-i)%4<2
end
puts x
this should work
For fun, using lazy enumerables (requires Ruby 2.0 or gem enumerable-lazy):
(2..Float::INFINITY).step(4).lazy.map(&:to_i).flat_map { |x| [x, x+1] }.first(8)
#=> => [2, 3, 6, 7, 10, 11, 14, 15]
here's a solution that works with infinite streams:
enum = Enumerator.new do |y|
(2...1/0.0).each_slice(4) do |slice|
slice[0 .. 1].each { |n| y.yield(n) }
end
end
enum.first(10) #=> [2, 3, 6, 7, 10, 11, 14, 15, 18, 19]
enum.each do |n|
puts n
end
Single Liner:
(0..20).to_a.reduce([0,[]]){|(count,arr),ele| arr << ele if count%4 > 1;
[count+1,arr] }.last
Explanation:
Starts the reduce look with 0,[] in count,arr vars
Add current element to array if condition satisfied. Block returns increment and arr for the next iteration.
I agree though that it is not so much of a single liner though and a bit complex looking.
Here's a slightly more general version of Sergio's fine answer
module Enumerable
def every_other(slice=1)
mod = slice*2
res = select.with_index { |_, i| i % mod >= slice }
block_given? ? res.map{|x| yield(x)} : res
end
end
irb> (0...20).every_other
=> [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
irb> (0...20).every_other(2)
=> [2, 3, 6, 7, 10, 11, 14, 15, 18, 19]
irb> (0...20).every_other(3)
=> [3, 4, 5, 9, 10, 11, 15, 16, 17]
irb> (0...20).every_other(5) {|v| v*10 }
=> [50, 60, 70, 80, 90, 150, 160, 170, 180, 190]

Resources