Related
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]
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]
Problem:
I have two arrays A and B:
A = [0, 1, 2, 3]; %A will always be from 0 to N where N in this case is 3.
B = [0, 1, 3, 1, 9, 4, 6, 2, 5, 9, 10, 11, 3, 8, 1, 5, 9, 10];
weights_B = [3, 4, 5, 6];
I want to compare the first element of A to the first 3 elements of B and the second element of A to the next 4 elements of B. If the elements of A are equal I remove it from B. So in example:
if (A(1) == B(1:3))
remove A(1) from B
Similarly,
I want to compare A(2) to the next 4 elements of B i.e. to B(4:7):
if (A(2) == B(4:7))
remove A(2) from B
I want to compare A(3) to the next 5 elements of B i.e. to B(8:12)
if (A(3) == B(8:12))
remove A(3) from B
I want to compare A(4) to the next 6 elements of B i.e. to B(13:18)
if (A(4) == B(13:18))
remove A(4) from B
Note: The array weights_B determines the number of elements in B that should be respectively compared to A(1), A(2), .. , A(4)
So in the end B should have the following elements:
B = [1, 3, 9, 4, 6, 5, 9, 10, 11, 8, 1, 5, 9, 10];
Needed Solution:
Is there any way I can do this without having to hard-code the indices?
Here's a way without hard-coding:
Bw = mat2cell(B, 1, weights_B); % split into chunks
result = cell(size(Bw)); % initiallize result
for k = 1: numel(A)
result{k} = Bw{k}(Bw{k}~=A(k)); % fill each chunk of the result
end
result = [result{:}]; % concatenate into a row vector
For the sake of diversity, here's a way to do this using splitapply:
function out = q50982235
A = 0:3;
B = [0, 1, 3, 1, 9, 4, 6, 2, 5, 9, 10, 11, 3, 8, 1, 5, 9, 10];
weights_B = [3, 4, 5, 6];
a_ind = 0; % acts as a "global" variable for the inner function
G = repelem( 1:numel(weights_B), weights_B ); % this creates a vector of groups
out = cell2mat( splitapply(#movdif, B, G) );
function out = movdif(B)
a_ind = a_ind + 1;
out = {B(B ~= A(a_ind))};
end
end
The above works because the order of processed groups is predictable.
This solution requires R2015b.
Try this
A = [0, 1, 2, 3];
B = [0, 1, 3, 1, 9, 4, 6, 2, 5, 9, 10, 11, 3, 8, 1, 5, 9, 10];
weights_B = A + A(end);
border_0 = zeros(size(A));
border_1 = zeros(size(A));
border_0(1) = 1;
border_1(end) = length(B);
for i= 2:length(A)
border_0(i) = border_0(i-1) + weights_B(i-1);
border_1(i-1) = border_0(i)-1;
end
C = [];
for i= 1:length(border_0)
shift = 0;
if (i > 1)
shift = border_1(i-1);
end
C = [C B( find(B(border_0(i):border_1(i))~=A(i)) + shift )]
end
A = [0, 1];
B = [0, 1, 3, 1, 4, 5, 6];
% Split B into cells
C{1} = B(1:3) ; % this can be coded if more splits are required
C{2} = B(4:end) ;
% removing the lements
for i = 1:2
C{i}(C{i}==A(i))=[] ; % remove the elements in C{i} present in A(i)
end
cell2mat(C)
Since you want to compare the elements of A with first 3 and then 4 elements of B respectively, you would need to involve indexes.
You could simply use loop for it.
for(int i=0;i<B.length;i++){
if((A[0]==B[i])&&i<3){
B[i]=B[i+1];
}
else if((A[0]==B[i])&&i>3){}
B[i]=B[i+1];
}
Then adjust the updated size of array B.
Problem Question
Divisors of 42 are : 1, 2, 3, 6, 7, 14, 21, 42. These divisors squared are: 1, 4, 9, 36, 49, 196, 441, 1764. The sum of the squared divisors is 2500 which is 50 * 50, a square!
Given two integers m, n (1 <= m <= n) we want to find all integers between m and n whose sum of squared divisors is itself a square. 42 is such a number.
The result will be an array of arrays, each subarray having two elements, first the number whose squared divisors is a square and then the sum of the squared divisors.
Code below
How can I make this specific program run faster? My current code times out after n > 9999.
#returns the divisors of each number in an array of arrays
r = (m..n).to_a.map { |z| (1..z).select { |x| z % x == 0} }
#this finds all integers between m and n whose sum of squared divisors is itself a square
squarenumbers = r.map { |x| x.map { |c| c**2 }.inject(:+) }.select { |x| Math.sqrt(x) % 1 == 0 }
#returns an array of booleans.
booleans = r.map { |x| x.map { |c| c**2 }.inject(:+) }.map { |x| Math.sqrt(x) % 1 == 0 }
#returns the index of each of the true values in booleans as an array
indexer = booleans.map.with_index{|x, i| i if x == true }.compact
#returns the numbers whose squared divisors is a square in an array
unsqr = indexer.map { |x| (m..n).to_a[x] }
#merges the two arrays together, element for element and creates an array of arrays
unsqr.zip(squarenumbers)
# for m = 1 and n = 1000 the result would be
# [[1, 1], [42, 2500], [246, 84100], [287, 84100], [728, 722500]]
Brute-force calculatioins of factors
You begin by calculating:
m, n = 40, 42
r = (m..n).to_a.map { |z| (1..z).select { |x| z % x == 0} }
#=> [[1, 2, 4, 5, 8, 10, 20, 40], [1, 41], [1, 2, 3, 6, 7, 14, 21, 42]]
That's OK, but you don't need .to_a:
r = (m..n).map { |z| (1..z).select { |x| z % x == 0} }
#=> [[1, 2, 4, 5, 8, 10, 20, 40], [1, 41], [1, 2, 3, 6, 7, 14, 21, 42]]
This avoids an extra step, which is the creation of the temporary array1,2:
(m..n).to_a #=> [40, 41, 42]
Structure of a solution
Let's work backwards to come up with our code. First, concentrate on determining, for any given number q, if the sum of squares of the factors of q is itself a perfect square. Suppose we construct a method magic_number? which takes q as its only argument and returns true if q satisfies the required property and false otherwise. Then we will compute:
(m..n).select { |q| magic_number?(q) }
to return an array of all numbers between m and n that satisfy the property. magic_number? can be written like this:
def magic_number?(q)
return true if q == 1
s = sum_of_squared_factors(q)
s == Math.sqrt(s).round**2
end
Calculating sum of squared factors
So now we are left with writing the method sum_of_squared_factors. We can use your code to obtain the factors:
def factors(q)
(1..q).select { |x| q % x == 0 }
end
factors(40) #=> [1, 2, 4, 5, 8, 10, 20, 40]
factors(41) #=> [1, 41]
factors(42) #=> [1, 2, 3, 6, 7, 14, 21, 42]
and then write:
def sum_of_squared_factors(q)
factors(q).reduce(0) { |t,i| t + i*i }
end
sum_of_squared_factors(40) #=> 2210
sum_of_squared_factors(41) #=> 1682
sum_of_squared_factors(42) #=> 2500
Speeding the calculation of factors
There's something more we can do to speed up the calculation of factors. If f is a factor of n, f and n/f, are both factors of n. (For example, since 3 is a factor of 42, so is 42/3 #=> 14). We therefore need only obtain the smaller of each pair.
There is one exception to this rule. If n is a perfect square and f == n**0.5, then f = n/f, so we only include f among the factors of n (not n/f as well).
If turns out that if f is the smaller of the pair, f <=(n**0.5).round3. We therefore need only check to see which of the numbers (1..(n**0.5).round) are factors and include their complements (unless n is a perfect square, in which case we do not double-count (n**0.5).round):
q = 42
arr = (1..Math.sqrt(q).round).select { |x| q % x == 0 }
#=> [1, 2, 3, 6]
arr = arr.flat_map { |n| [n, q/n] }
#=> [1, 42, 2, 21, 3, 14, 6, 7]
arr.pop if a[-2] == a[-1]
arr
#=> [1, 42, 2, 21, 3, 14, 6, 7]
q = 36
arr = (1..Math.sqrt(q).round).select { |x| q % x == 0 }
#=> [1, 2, 3, 4, 6]
arr = arr.flat_map { |n| [n, q/n] }
#=> [1, 36, 2, 18, 3, 12, 4, 9, 6, 6]
arr.pop if a[-2] == a[-1]
#=> 6
arr
#=> [1, 36, 2, 18, 3, 12, 4, 9, 6]
so we can write:
def factors(q)
arr = (1..Math.sqrt(q)).select { |x| q % x == 0 }
arr = arr.flat_map { |n| [n, q/n] }
arr.pop if arr[-2] == arr[-1]
arr
end
Substituting out arr ("chaining" expressions), we obtain a typical Ruby expression:
def factors(q)
(1..Math.sqrt(q)).select { |x| q % x == 0 }.
flat_map { |n| [n, q/n] }.
tap { |a| a.pop if a[-2] == a[-1] }
end
factors(42)
#=> [1, 42, 2, 21, 3, 14, 6, 7]
factors(36)
#=> [1, 36, 2, 18, 3, 12, 4, 9, 6]
See Enumerable#flat_map and Object#tap. (There's no need for this array to be sorted. In applications where it needs to be sorted, just tack .sort onto the end of flat_maps block.)
Wrapping up
In sum, we are left with the following:
def magic_number?(q)
return true if q == 1
s = sum_of_squared_factors(q)
s == Math.sqrt(s).round**2
end
def sum_of_squared_factors(q)
factors(q).reduce(0) { |t,i| t + i*i }
end
def factors(q)
(1..Math.sqrt(q)).select { |x| q % x == 0 }.
flat_map { |n| [n, q/n] }.
tap { |a| a.pop if a[-2] == a[-1] }
end
m, n = 1, 1000
(m..n).select { |q| magic_number?(q) }
#=> `[1, 42, 246, 287, 728]
This calculation was completed in a blink of an eye.
Compute primes to further speed calculation of factors
Lastly, let me describe an even faster way to compute the factors of a number, using the method Prime::prime_division. That method decomposes any number into its prime components. Consider, for example, n = 360.
require 'prime'
Prime.prime_division(360)
#=> [[2, 3], [3, 2], [5, 1]]
This tells us that:
360 == 2**3 * 3**2 * 5**1
#=> true
It also tells us that every factor of 360 is the product of between 0 and 3 2's, multiplied by between 0 and 2 3's, multiplied by 0 or 1 5's. Therefore:
def factors(n)
Prime.prime_division(n).reduce([1]) do |a,(prime,pow)|
a.product((0..pow).map { |po| prime**po }).map { |x,y| x*y }
end
end
a = factors(360).sort
#=> [ 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 18,
# 20, 24, 30, 36, 40, 45, 60, 72, 90, 120, 180, 360]
We can check that:
a == (1..360).select { |n| (360 % n).zero? }
#=> true
One other check:
factors(40).sort
#=> [1, 2, 4, 5, 8, 10, 20, 40]
1. You could instead write that [*m..n] #=> [40, 41, 42].
2. Why is it not necessary to convert the range to an array? Enumerable#map, being an instance method of the module Enumerable, is available for use by every class that includes Enumerable. Array is one, but (m..n).class #=> Range is another. (See the second paragraph at Range).
3. Suppose f is smaller than n/f and f > n**0.5, then n/f < n/(n**0.5) = n**0.5 < f, a contradiction.
I don't know Ruby but the problem lies with the algorithm used in finding the divisors of a number (which is not specific to the language used, i.e. Ruby in this case).
r = (m..n).to_a.map { |z| (1..z).select { |x| z % x == 0} }
To find the divisors of an integer n you are dividing n by all positive integers unto n - 1 which means the loop runs n - 1 times. However, it is enough to divide upto sort(n) to calculate the divisors. In pseudocode this looks like below:
for i = 1 to i <= sqrt(n)
r = n % i
if r == 0 then
i is a divisor
if n / i != i then
n / i is another divisor
For example:
sqrt_42 = 6.48074069840786
i = 1 => 1 and 42 are two divisors
i = 2 => 2 and 21
i = 3 => 3 and 14
i = 4 => no divisor
i = 5 => no divisor
i = 6 => 6 and 7
And thats all.
This will improve the performance a lot since now the loop runs only sort(n) times instead of n - 1 times which is a big difference for large n.
I have a data set like the following:
x= [1, 4, 10]
y= [10, 20, 30]
(x and y are value pairs, i.e. (1,10), (4,20), (10,30))
I would like to fill the x values gaps and having constant values for y until the next known value pair comes.This should be done between each value pair, i.e. between (1,10) and (4,20) and then again between (4,20) and (10,30).
Input:
x=[1, 4, 10];
y=[10, 20, 30];
Output:
xi= [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
yi= [10,10, 10, 20, 20, 20, 20, 20, 20, 30];
How can Matlab solve this for me?
Assuming ascending order of elements in x, this could be one approach based on diff & cumsum -
%// Sample inputs
x=[1, 4, 10]
y=[-2, 5, -3]
xi = min(x):max(x)
yi = zeros(1,numel(xi))
yi(x) = diff([0 y])
yi = cumsum(yi)
Sample run -
x =
1 4 10
y =
-2 5 -3
xi =
1 2 3 4 5 6 7 8 9 10
yi =
-2 -2 -2 5 5 5 5 5 5 -3
Customary bsxfun solution to get yi -
lens = [diff(x) 1];
yi = nonzeros(bsxfun(#times,bsxfun(#ge,lens,[1:max(lens)]'),y)).'
Assuming that x always starts with a 1 and finishes with the final length of xi, this will work:
xi=1:x(end)
yi=y(arrayfun(#(xi)find(x<=xi,1,'last'),xi))