Proper way to make array from integer division in Ruby - arrays

tl;dr I want to make an array from the division by 5 results:
20 => [5,5,5,5]
16 => [5,5,5,1]
7 => [5,2]
My current implementation is straightforward yet too large. How can I make it simpler and shorter?
max_count = 5
total_count = input_value
count_array = []
div = total_count / max_count
mod = total_count % max_count
div.times { count_array << max_count }
count_array << mod unless mod == 0

You don't need total_count.
div.times { count_array << max_count } is [max_count] * count_array
Using splat, we can simplify it further
max_count = 5
[*[max_count] * (input_value / max_count), input_value % max_count] - [0]
Alternatively, using divmod
max_count = 5
n, mod = input_value.divmod(max_count)
[*[max_count] * n, mod] - [0]
Last line can also be written as:
(Array.new(n) { max_count } << mod) - [0]
or as Stefan suggested in the comment, using Numeric#nonzero?:
Array.new(n, max_count).push(*mod.nonzero?)

One option more:
d = 5
n = 24
Array.new(n/d){d}.tap{ |a| a << n%d if (n%d).nonzero? }
#=> [5, 5, 5, 5, 4]

You can try this as well.
max=5
num=48
q, r=num.divmod(max) # => [9, 3]
Array.new.fill(max, 0, q).push(r.nonzero?).compact
# => [5, 5, 5, 5, 5, 5, 5, 5, 5, 3]

What about this?
[20].tap{|a| a.push(5, a.pop - 5) while a.last > 5} # => [5, 5, 5, 5]
[16].tap{|a| a.push(5, a.pop - 5) while a.last > 5} # => [5, 5, 5, 1]
[7] .tap{|a| a.push(5, a.pop - 5) while a.last > 5} # => [5, 2]

Related

Find subsequence of length k with the largest product

Language: Python
Given an array of integers, return the subsequence of length k which has the largest possible product. If there is more than one valid subsequence that gives the same product, return the one with the largest sum of numbers.
Example 1
array = [-10, -3, 5, 6, -2]
k = 2
Output should be [-10, -3] ( (-10) * (-3) = 30, which is the largest product of the given numbers)
Example 2
array = [10, 3, 5, 6, 20]
k = 3
Output should be [6, 10, 20], (6 * 10 * 20 = 1200)
Example 3
array = [1, -4, 3, -6, 7, 0]
k = 4
Output should be [-6, -4, 3, 7] ( (-6) * (-4) * 3 * 7 = 504)
I've already tried the code
def find_k_prod(arr, k):
arr = sorted(arr)
current_prod = 1
n = len(arr)
for i in range(k):
current_prod *= arr[n-1-i]
max_prod = current_prod
for i in range(k):
current_prod = (current_prod/arr[-(k-i)])*arr[i]
max_prod = max(current_prod, max_prod)
return max_prod
, but have no idea how to return the subsequence (not the product).

how to shrink an array if two consecutive numbers in an array are equal then remove one and increment other

How to shrink an array if two consecutive numbers in an array are equal then remove one and increment other
Example 1:
int a[6]={2,2,3,4,4,4};
// Output: 6
Example 2:
int b[7]={1,2,2,2,4,2,4};
// Output: {1,3,2,4,2,4}
lst = [2,2,3,4,4,4]
def shrink(lst):
idx = 0
while len(lst) > idx+1:
a, b = lst.pop(idx), lst.pop(idx)
if a == b:
lst.insert(idx, a+1)
idx = 0
else:
lst.insert(idx, b)
lst.insert(idx, a)
idx += 1
shrink(lst)
print(lst)
Prints:
[6]
For [5, 5, 5, 1] prints [6, 5, 1]
This can be done in near-linear time like so:
a = [2, 2, 3, 4, 4, 4]
b = [1, 2, 2, 2, 4, 2, 4]
c = [5, 5, 5, 1]
def shrink_array(a):
res = []
for i in range(1, len(a)+1):
if i < len(a) and a[i] == a[i-1]: # if equal to previous
a[i] += 1 # increment and move on
else:
if len(res) > 0 and res[-1] == a[i-1]: # if equal to last in res
res[-1] += 1 # increment last in res
else:
res.append(a[i-1]) # add to res
while len(res) > 1 and res[-1] == res[-2]: # shrink possible duplicates
res[-2] += 1
del res[-1]
return(res)
for arr in [a, b, c]:
print(shrink_array(arr))
Output:
[6]
[1, 3, 2, 4, 2, 4]
[6, 5, 1]

Inner String array swap

I try to swap inner string array value with none additional array, stack...etc.
Example:
s = [1,2,3,4,5,6,7,8]
output= [1,5,2,6,3,7,4,8]
My solution shows as below, but I think isn't the best solution. Can someone correct my code efficiency?
[python3]
class Solution:
def inner_number(self, s):
i=len(s)//2
index=1
while i < len(s):
for j in range(i,index,-1):
s[j-1],s[j]=s[j],s[j-1]
i+=1
index+=2
return s
s = [1,2,3,4,5,6,7,8,9]
h = len(s)//2
res= []
if len(s)%2==1:
res = [j for i in zip(s[:h],s[h:]) for j in i] + [s[-1]]
else:
res = [j for i in zip(s[:h],s[h:]) for j in i]
print(res)
# output [1, 5, 2, 6, 3, 7, 4, 8, 9]
def inner_swap(input):
req_length = int(len(input)/2) if len(input) % 2 == 0 else int(len(input)/2)+1
s1 = input[:req_length]
s2 = input[req_length:]
result = [None]*len(input)
result[::2] = s1
result[1::2] = s2
return result
assert inner_swap([1, 2, 3, 4]) == [1, 3, 2, 4]
assert inner_swap([1, 2, 3, 4, 5]) == [1, 4, 2, 5, 3]

Merge two ordered arrays into one ordered array

I am writing a method that takes two sorted arrays and I want it to return a merged array with all the values sorted. Given the two arrays below:
array_one = [3, 4, 8]
array_two = [1, 5, 7]
I want my merge_arrays method to return:
[1, 3, 4, 5, 7, 8]
My current algorithm is below:
def merge_arrays(array_one, array_two)
merged_array_size = array_one.length + array_two.length
merged_array = []
current_index_on_one = 0
current_index_on_two = 0
current_merged_index = 0
for i in (0..merged_array_size - 1)
if array_one[current_index_on_one] < array_two[current_index_on_two]
merged_array[current_merged_index] = array_one[current_index_on_one]
current_index_on_one += 1
current_merged_index += 1
else
merged_array[current_merged_index] = array_two[current_index_on_two]
current_index_on_two += 1
current_merged_index += 1
end
end
return merged_array
end
I am getting an error 'undefined method `<' for nil:NilClass'. I don't understand how the conditional is receiving this. I debugged the variables in the conditionals and they are giving true or false values. I'm not sure what is causing this error.
Maybe I am missing the point but you can do:
(array_one + array_two).sort
=> [1, 3, 4, 5, 7, 8]
I am getting an error 'undefined method `<' for nil:NilClass'. I don't understand how the conditional is receiving this.
You start by comparing index 0 to index 0:
[3, 4, 8] [1, 5, 7]
0-----------0 #=> 3 < 1
Then you increment the lower value's index by 1:
[3, 4, 8] [1, 5, 7]
0--------------1 #=> 3 < 5
And so on:
[3, 4, 8] [1, 5, 7]
1-----------1 #=> 4 < 5
[3, 4, 8] [1, 5, 7]
2--------1 #=> 8 < 5
[3, 4, 8] [1, 5, 7]
2-----------2 #=> 8 < 7
At that point you get:
[3, 4, 8] [1, 5, 7]
2--------------3 #=> 8 < nil
Index 3 is outside the array's bounds, so array_two[current_index_on_two] returns nil and:
if array_one[current_index_on_one] < array_two[current_index_on_two]
# ...
end
becomes
if 8 < nil
# ...
end
resulting in ArgumentError(comparison of Integer with nil failed). If nil is on the left hand side, you'd get NoMethodError (undefined method `<' for nil:NilClass).
Here's one way you can write merge using recursion. Note, as you specified, both inputs must already be sorted otherwise the output will be invalid. The inputs can vary in size.
def merge (xs, ys)
if xs.empty?
ys
elsif ys.empty?
xs
else
x, *_xs = xs
y, *_ys = ys
if x < y
[x] + (merge _xs, ys)
else
[y] + (merge xs, _ys)
end
end
end
merge [ 1, 3, 4, 6, 8, 9 ], [ 0, 2, 5, 7 ]
# => [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
Assuming you have two sorted arrays. You need to create pipeline using recursion going to crunch through each array. checking at each iteration to see
which value at index 0 of either array is lower, removing that from the array and appending that value to the result array.
def merge_arrays(a, b)
# build a holder array that is the size of both input arrays O(n) space
result = []
# get lower head value
if a[0] < b[0]
result << a.shift
else
result << b.shift
end
# check to see if either array is empty
if a.length == 0
return result + b
elsif b.length == 0
return result + a
else
return result + merge_arrays(a, b)
end
end
> a = [3, 4, 6, 10, 11, 15]
> b = [1, 5, 8, 12, 14, 19]
> merge_arrays(a, b)
#=> [1, 3, 4, 5, 6, 8, 10, 11, 12, 14, 15, 19]
I made slight changes to your code in order to make it work. See the comments inside.
array_one = [2, 3, 4, 8, 10, 11, 12, 13, 15]
array_two = [1, 5, 6, 7, 9, 14]
def merge_arrays(array_one, array_two)
array_one, array_two = array_two, array_one if array_one.length > array_two.length # (1) swap arrays to make satement (3) work, need array_two always be the longest
merged_array_size = array_one.length + array_two.length
merged_array = []
current_index_on_one = 0
current_index_on_two = 0
current_merged_index = 0
for i in (0...merged_array_size-1) # (2) three points to avoid the error
if (!array_one[current_index_on_one].nil? && array_one[current_index_on_one] < array_two[current_index_on_two]) # (3) check also if array_one is nil
merged_array[current_merged_index] = array_one[current_index_on_one]
current_index_on_one += 1
current_merged_index += 1
else
merged_array[current_merged_index] = array_two[current_index_on_two]
current_index_on_two += 1
current_merged_index += 1
end
end
merged_array[current_merged_index] = array_one[current_index_on_one] || array_two[current_index_on_two] # (4) add the missing element at the end of the loop, looks what happen if you comment out this line
return merged_array
end
p merge_arrays(array_one, array_two)
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
The error was coming because the loop was making one step over. The solution is to stop before and insert the missing element at the end of the loop.
It works also with:
# for i in (1...merged_array_size)
# and
# for i in (1..merged_array_size-1)
# and
# (merged_array_size-1).times do
arr1 = [3, 4, 8, 9, 12]
arr2 = [1, 5, 7, 8, 13]
arr = [arr1, arr2]
idx = [0, 0]
(arr1.size + arr2.size).times.with_object([]) do |_,a|
imin = [0, 1].min_by { |i| arr[i][idx[i]] || Float::INFINITY }
a << arr[imin][idx[imin]]
idx[imin] += 1
end
#=> [1, 3, 4, 5, 7, 8, 8, 9, 12, 13]

Ruby - How do you perform an operation on each item of two (maybe more) arrays and populate them in a new array?

a = [6, 7, 8, 9, 10]
b = [1, 2, 3, 4, 5]
each of array a's items are divided by each of array b's items and put into a new array called c.
c = [6, 3, 2, 2, 2]
a = [6, 7, 8, 9, 10]
b = [1, 2, 3, 4, 5]
c = a.zip(b).map { |e| e.reduce :/ }
#⇒ [
# [0] 6,
# [1] 3,
# [2] 2,
# [3] 2,
# [4] 2
# ]
Array#zip zips the arrays together and then each element (array of 2 items zipped) is reduced with Integer#/.
I like mudasobwa's zip/map solution, but here are a couple alternatives:
a = [6, 7, 8, 9, 10]
b = [1, 2, 3, 4, 5]
c = Array.new(a.size) { |i| a[i] / b[i] }
c = a.map.with_index { |x, i| x / b[i] }
In particular, I might prefer the Array.new solution if the arrays aren't guaranteed to be the same length, because you can easily ensure you don't go over bounds:
c = Array.new([a.size, b.size].min) { |i| a[i] / b[i] }

Resources