Using formula and counter in an array - ruby

What I have is:
array.map!{
|c| c*(y**(z-1))
z=z+1
}
array contains
[10, 10, 10]
The output isn't what I want, it is
[2, 3, 4]
I want the z to function as a counter, it was defined earlier as 1, and the y was defined earlier. also, as 16 or 36 (depending on user input)
So if I input the same array with 3 10s. I want array to be (when the y is 16):
[10, 160, 2560]

There are more idiomatic ways to achieve this in ruby, for instance:
y = 16
array = Array.new(3) { |i| 10*(y**i) }
# => [10, 160, 2560]
Or alternatively, if the contents are not always the constant 10, there is this:
y = 16
array = [10, 10, 10]
array.map!.with_index { |c, i| c*(y**i) }
# => [10, 160, 2560]
The above two examples leave the indexing to the looping construct, which is good, because it's one less thing for you to worry about.

Write it as
z = 1; y =16
array = [10, 10, 10]
array.map { |c| z=z+1 ; c*(y**(z-2)) }
# => [10, 160, 2560]
With Array#map, block returned the last expression for each iteration. In your case it was z = z + 1. Your initial z was 1. So in your first z = z+1 evaluated and it was 2, next iteration it incremented again by 1, so value of z is 3, same way in the last pass z becomes 4. So finally you got the new array as [2, 3, 4].
One Rubyish way :
y = 16
3.times.map{|i| 10*y**i} # => [10, 160, 2560]

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.

How to add data to array and apply increase Qty for that?

hi i have an array that dimension after mining push to that how can i increase Qty after each pushing for similar dimension?
suppose to we have this array:
[x,y,Qty]
b=[]
b.push[100,50,1]
b.push[20,30,1]
b.push[100,50,1]
b.push[10,60,1]
how can i have this result: b = [ [100,50,2],[20,30,1],[10,60,1] ]
Suppose we are given the following (which differs slightly from the example).
b = [[100, 50, 1], [20, 30, 2], [100, 50, 1], [10, 60, 1]]
Let's begin with a relatively inefficient solution and then see how it can be improved.
Staightforward but relatively inefficient solution
We first compute the following array.
arr = b.map { |x,y,z| [x, y] }
#=> [[100, 50], [20, 30], [100, 50], [10, 60]]
Before continuing suppose b were to change in future such that each element contain four, rather than three, values, such as [100, 50, 20, 2]. We could change the calculation of arr to arr = b.map { |w,x,y,z| [w, x, y] }, but a better solution is to use the splat operator, *, to perform Array#decomposition. By using the splat operator we need not change this code if the size of the elements of b changes.
arr = b.map { |*a,z| a }
#=> [[100, 50], [20, 30], [100, 50], [10, 60]]
For each element (array) e of b, the array a will contain all but the last element of e and z will contain the last element of e, regardless of the size of e.
Next we use the method Array#uniq to obtain the unique elements of arr.
arr_uniq = arr.uniq
#=> [[100, 50], [20, 30], [10, 60]]
We may then compute the desired array as follows.
arr_uniq.map do |a|
tot = 0
b.each { |*c,z| tot += z if a == c }
[*a, tot]
end
#=> [[100, 50, 2], [20, 30, 2], [10, 60, 1]]
Recall that tot += z is effectively the same as tot = tot + z.
This approach is relatively inefficient because the array b is traversed completely for each element of arr_uniq. We should be able to make only a single pass through b.
Improving efficiency
We step through each element of b to construct a hash.
h = {}
b.each do |*a,z|
if h.key?(a)
h[a] += z
else
h[a] = z
end
end
h #=> {[100, 50]=>2, [20, 30]=>2, [10, 60]=>1}
We now need only convert h to the desired array (though it may be more useful to stop here and use the hash for subsequent calculations).
h.map { |k,v| [*k, v] }
#=> [[100, 50, 2], [20, 30, 2], [10, 60, 1]]
We now consider how to make this calculation more Ruby-like.
Wrapping up
To improve upon the construction of h above we make use of two methods: the form of class method Hash::new that takes an argument called the default value; and Enumerable#each_with_object.
b.each_with_object(Hash.new(0)) { |(*a,z),h| h[a] += z }
.map { |k,v| [*k, v] }
#=> [[100, 50, 2], [20, 30, 2], [10, 60, 1]]
This first step is to compute a hash:
b.each_with_object(Hash.new(0)) { |(*a,z),h| h[a] += z }
#=> {[100, 50]=>2, [20, 30]=>2, [10, 60]=>1}
You may wish to review the link to array decomposition that I gave earler to see how the block variables a, z and h in |(*a,z),h| are assigned values.
If a hash is defined
h = Hash.new(0)
h[k] returns the default value, here zero, if h does not contain a key k.
Initially,
h[[100, 50]] += 1
expands to
h[[100, 50]] = h[[100, 50]] + 1
Since h has no keys at this time--specifically no key [100, 50]--h[[100, 50]] on the right returns the default value, so the expression becomes
h[[100, 50]] = 0 + 1
h #=> { [100, 50] => 1 }
Later, when the same key [100, 50] is encountered (when h #=> { [100, 50] => 1, [20, 30] => 2 }), the expresson becomes
h[[100, 50]] = 1 + 1
h #=> { [100, 50] => 2, [20, 30] => 2 }
This time, h has a key [100, 50], so h[[100, 50]] on the right returns its value, which equals 1 (and the default value is not used).
Alternative method: use Enumerable#group_by
We could alternatively compute the desired array as follows.
b.group_by { |*a,z| a }
.map { |k,v| [*k, v.sum(&:last)] }
#=> [[100, 50, 2], [20, 30, 2], [10, 60, 1]]
The first step is to compute a hash:
b.group_by { |*a,z| a }
#=> {[100, 50]=>[[100, 50, 1], [100, 50, 1]],
[20, 30]=>[[20, 30, 2]], [10, 60]=>[[10, 60, 1]]}
When compared to the method above that employs Hash::new, this calculation has the minor disadvantage that the memory requirements for the values in the intermediate are somewhat greater.

Codewars exercise "Count by X" not working

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

Recursive merge sort in Ruby

I am trying to write a ruby method which performs a merge sort recursively. I have the method working, but It's one of those times where I accidentally got it working so I have no idea WHY it works, and would love to understand how the code I have written works. In psuedocode, the steps I followed look like this.
Split the original array of length n until I have n arrays of length 1
Merge and sort 2 arrays of length m at time to return an array of length m*2
Repeat the step above until I have a single now sorted array of length n
Basically what this looks like to me is a large tree branching out into n branches, with each branch containing an array of length 1. Then I need to take these n branches and somehow merge them back into a single branch within the method.
def merge_sort(arr)
return arr if arr.length == 1
merge(merge_sort(arr.slice(0, arr.length/2)),
merge_sort(arr.slice(arr.length/2, arr[-1])))
end
def merge(arr1, arr2)
sorted = []
begin
less_than = arr1[0] <=> arr2[0]
less_than = (arr1[0] == nil ? 1 : -1) if less_than == nil
case less_than
when -1
sorted << arr1[0]
arr1 = arr1.drop(1)
when 0
sorted << arr1[0]
sorted << arr2[0]
arr1 = arr1.drop(1)
arr2 = arr2.drop(1)
when 1
sorted << arr2[0]
arr2 = arr2.drop(1)
end
end until (arr1.length == 0 && arr2.length == 0)
sorted
end
merge_sort([1,6,3,8,22,3,11,24,54,68,79,80,98,65,46,76,53])
#Returns => [1, 3, 3, 6, 8, 11, 22, 24, 46, 53, 54, 65, 68, 76, 79, 80, 98]
The method I have actually correctly sorts the list, but I am not totally sure how the method combines each branch and then returns the sorted merged list, rather than just the first two length one arrays it combines.
Also, If anyone has ideas for how I can make the merge method prettier to look more like the ruby code I have grown to love please let me know.
Here is my implementation of mergesort in Ruby
def mergesort(array)
return array if array.length == 1
middle = array.length / 2
merge mergesort(array[0...middle]), mergesort(array[middle..-1])
end
def merge(left, right)
result = []
until left.length == 0 || right.length == 0 do
result << (left.first <= right.first ? left.shift : right.shift)
end
result + left + right
end
As you can see, the mergesort method is basically the same as yours, and this is where the recursion occurs so that is what I will focus on.
First, you have your base case: return array if array.length == 1 This is what allows the recursion to work and not go on indefinitely.
Next, in my implementation I have defined a variable middle to represent the middle of the array: middle = array.length / 2
Finally, the third line is where all the work occurs: merge mergesort(array[0...middle]), mergesort(array[middle..-1])
What you are doing here is telling the merge method to merge the mergesorted left half with the mergesorted right half.
If you assume your input array is [9, 1, 5, 4] what you are saying is merge mergesort([9, 1]), mergesort([5, 4]).
In order to perform the merge, you first have to mergesort [9, 1] and mergesort [5, 4]. The recursion then becomes
merge((merge mergesort([9]), mergesort([1])), (merge mergesort([5]), mergesort([4])))
When we recurse again, the mergesort([9]) has reached the base case and returns [9]. Similarly, mergesort([1]) has also reached the base case and returns [1]. Now you can merge [9] and [1]. The result of the merge is [1, 9].
Now for the other side of the merge. We have to figure out the result of merge mergesort([5]), mergesort([4]) before we can merge it with [1, 9]. Following the same procedure as the left side, we get to the base case of [5] and [4] and merge those to get [4, 5].
Now we need to merge [1, 9] with [4, 5].
On the first pass, result receives 1 because 1 <= 4.
On the next pass, we are working with result = [1], left = [9], and right = [4, 5]. When we see if left.first <= right.first we see that it is false, so we return right.shift, or 4. Now result = [1, 4].
On the third pass, we are working with result = [1, 4], left = [9], and right = [5]. When we see if left.first <= right.first we see that it is false, so we return right.shift, or 5. Now result = [1, 4, 5].
Here the loop ends because right.length == 0.
We simply concatenate result + left + right or [1, 4, 5] + [9] + [], which results in a sorted array.
Here is my version of a recursive merge_sort method for Ruby. Which does the exact same as above, but slightly different.
def merge_sort(array)
array.length <= 1 ? array : merge_helper(merge_sort(array[0...array.length / 2]), merge_sort(array[array.length / 2..-1]))
end
def merge_helper(left, right, merged = [])
left.first <= right.first ? merged << left.shift : merged << right.shift until left.length < 1 || right.length < 1
merged + left + right
end
p merge_sort([]) # => []
p merge_sort([20, 8]) # => [8, 20]
p merge_sort([16, 14, 11]) # => [11, 14, 16]
p merge_sort([18, 4, 7, 19, 17]) # => [4, 7, 17, 18, 19]
p merge_sort([10, 12, 15, 13, 16, 7, 19, 2]) # => [2, 7, 10, 12, 13, 15, 16, 19]
p merge_sort([3, 14, 10, 8, 11, 7, 18, 17, 2, 5, 9, 20, 19]) # => [2, 3, 5, 7, 8, 9, 10, 11, 14, 17, 18, 19, 20]

Ruby: How to find the index of the minimum array element?

Is there any way to rewrite this more elegant? I think, that it's a bad piece of code and should be refactored.
>> a = [2, 4, 10, 1, 13]
=> [2, 4, 10, 1, 13]
>> index_of_minimal_value_in_array = a.index(a.min)
=> 3
I believe this will traverse the array only once and is still easy to read:
numbers = [20, 30, 40, 50, 10] # => [20, 30, 40, 50, 10]
elem, idx = numbers.each_with_index.min # => [10, 4]
This traverses the array only once whereas ary.index(ary.min) would traverse it twice:
ary.each_with_index.inject(0){ |minidx, (v,i)| v < a[minidx] ? i : minidx }
It would be interesting to read about other situations (finding all and only last minimal element).
ary = [1, 2, 1]
# find all matching elements' indexes
ary.each.with_index.find_all{ |a,i| a == ary.min }.map{ |a,b| b } # => [0, 2]
ary.each.with_index.map{ |a, i| (a == ary.min) ? i : nil }.compact # => [0, 2]
# find last matching element's index
ary.rindex(ary.min) # => 2
I actually like #andersonvom 's answer, it only need to loop the array once and still get the index.
And in case you don't want to use ary.each_with_index.min, here is what you can do:
ary = [2,3,4,5,1] # => [2,3,4,5,1]
_, index_of_minimal_value_in_array = ary.each_with_index.min # => [1, 4]
index_of_minimal_value_in_array # => 4

Resources