Split array into subarrays by summed up value - arrays

I have an array of hashes, where every hash has a size key:
blocks = [{size: 1},{size: 3},{size: 4}]
Now I want to split this array into subarrays by aggregating the size value, and defining an upper limit of 4. In every subarray the summed up values of the size key should be less than 4.
I have this solution, but it's not pretty or elegant:
arr = []
tmp = []
sum = 0
blocks.each do |block|
sum += block[:size]
tmp.push(block)
if sum >= 4
arr.push(tmp)
sum = 0
tmp = []
end
end
Maybe someone knows a more ruby-like, elegant solution.

There is a way using slice_when:
sum = 0
blocks.slice_when do |elt_before, _|
sum += elt_before[:size]
sum >= 4 ? (sum = 0; true) : false
end.to_a
Edit: As per #CarySwoveland suggestion
It can get even simpler if using slice_after:
sum = 0
blocks.slice_after do |elt|
sum += elt[:size]
sum >= 4 ? (sum = 0; true) : false
end.to_a
As a note both slice_when & slice_after first appeared in Ruby v.2.2

Related

Generate a matrix of combinations (permutation) without repetition (array exceeds maximum array size preference)

I am trying to generate a matrix, that has all unique combinations of [0 0 1 1], I wrote this code for this:
v1 = [0 0 1 1];
M1 = unique(perms([0 0 1 1]),'rows');
• This isn't ideal, because perms() is seeing each vector element as unique and doing:
4! = 4 * 3 * 2 * 1 = 24 combinations.
• With unique() I tried to delete all the repetitive entries so I end up with the combination matrix M1 →
only [4!/ 2! * (4-2)!] = 6 combinations!
Now, when I try to do something very simple like:
n = 15;
i = 1;
v1 = [zeros(1,n-i) ones(1,i)];
M = unique(perms(vec_1),'rows');
• Instead of getting [15!/ 1! * (15-1)!] = 15 combinations, the perms() function is trying to do
15! = 1.3077e+12 combinations and it's interrupted.
• How would you go about doing in a much better way? Thanks in advance!
You can use nchoosek to return the indicies which should be 1, I think in your heart you knew this must be possible because you were using the definition of nchoosek to determine the expected final number of permutations! So we can use:
idx = nchoosek( 1:N, k );
Where N is the number of elements in your array v1, and k is the number of elements which have the value 1. Then it's simply a case of creating the zeros array and populating the ones.
v1 = [0, 0, 1, 1];
N = numel(v1); % number of elements in array
k = nnz(v1); % number of non-zero elements in array
colidx = nchoosek( 1:N, k ); % column index for ones
rowidx = repmat( 1:size(colidx,1), k, 1 ).'; % row index for ones
M = zeros( size(colidx,1), N ); % create output
M( rowidx(:) + size(M,1) * (colidx(:)-1) ) = 1;
This works for both of your examples without the need for a huge intermediate matrix.
Aside: since you'd have the indicies using this approach, you could instead create a sparse matrix, but whether that's a good idea or not would depend what you're doing after this point.

adjacentElementsProduct function in ruby

I'm stuck on an algorithm for a function called adjacentElementsProduct that accepts an array as the argument. It's supposed to return the largest product of adjacent numbers in the array. For example, if the argument is [2,4,1,3,2,6] it would return 12 because of the pair of 2 and 6.
my code is
def adjacentElementsProduct(inputArray)
idx1 = 0
idx2 = 1
while idx2 < inputArray.length
pair = [inputArray[idx1], inputArray[idx1 + 1]]
next_pair = [inputArray[idx2], inputArray[idx2 + 1]]
if next_pair.reduce(:+) > pair.reduce(:+)
pair = next_pair
idx1 += 1
idx2 += 1
else
idx1 += 1
idx2 += 1
end
end
pair.reduce(:+)
end
I just can't figure out where my code is not working. I'm just looking for a push in the right direction because I know just being given the answer won't help me as much. Can anyone help me?
The code makes no sense :).
You are using + instead of *
And in the loop you always assign pair = [inputArray[idx1], inputArray[idx1 + 1]].
So you always return the last pair or the previous. If the maximum product is at the beginning, you still keep advancing the pair variable until the end of the loop.
Besides, the solution is quite complicated.
def adjacentElementsProduct(inputArray)
index = 0
length = inputArray.length
max = 0
while index < length-1 do
result = inputArray[index] * inputArray[index+1]
max = result if result > max
index += 1
end
max
end

Vectorizing a code that requires to complement some elements of a binary array

I have a matrix A of dimension m-by-n composed of zeros and ones, and a matrix J of dimension m-by-1 reporting some integers from [1,...,n].
I want to construct a matrix B of dimension m-by-n such that for i = 1,...,m
B(i,j) = A(i,j) for j=1,...,n-1
B(i,n) = abs(A(i,n)-1)
If sum(B(i,:)) is odd then B(i,J(i)) = abs(B(i,J(i))-1)
This code does what I want:
m = 4;
n = 5;
A = [1 1 1 1 1; ...
0 0 1 0 0; ...
1 0 1 0 1; ...
0 1 0 0 1];
J = [1;2;1;4];
B = zeros(m,n);
for i = 1:m
B(i,n) = abs(A(i,n)-1);
for j = 1:n-1
B(i,j) = A(i,j);
end
if mod(sum(B(i,:)),2)~=0
B(i,J(i)) = abs(B(i,J(i))-1);
end
end
Can you suggest more efficient algorithms, that do not use the nested loop?
No for loops are required for your question. It just needs an effective use of the colon operator and logical-indexing as follows:
% First initialize B to all zeros
B = zeros(size(A));
% Assign all but last columns of A to B
B(:, 1:end-1) = A(:, 1:end-1);
% Assign the last column of B based on the last column of A
B(:, end) = abs(A(:, end) - 1);
% Set all cells to required value
% Original code which does not work: B(oddRow, J(oddRow)) = abs(B(oddRow, J(oddRow)) - 1);
% Correct code:
% Find all rows in B with an odd sum
oddRow = find(mod(sum(B, 2), 2) ~= 0);
for ii = 1:numel(oddRow)
B(oddRow(ii), J(oddRow(ii))) = abs(B(oddRow(ii), J(oddRow(ii))) - 1);
end
I guess for the last part it is best to use a for loop.
Edit: See the neat trick by EBH to do the last part without a for loop
Just to add to #ammportal good answer, also the last part can be done without a loop with the use of linear indices. For that, sub2ind is useful. So adopting the last part of the previous answer, this can be done:
% Find all rows in B with an odd sum
oddRow = find(mod(sum(B, 2), 2) ~= 0);
% convert the locations to linear indices
ind = sub2ind(size(B),oddRow,J(oddRow));
B(ind) = abs(B(ind)- 1);

Array not defined

I'm still confused why am not able to know the results of this small algorithm of my array. the array has almost 1000 number 1-D. am trying to find the peak and the index of each peak. I did found the peaks, but I can't find the index of them. Could you please help me out. I want to plot all my values regardless the indexes.
%clear all
%close all
%clc
%// not generally appreciated
%-----------------------------------
%message1.txt.
%-----------------------------------
% t=linspace(0,tmax,length(x)); %get all numbers
% t1_n=0:0.05:tmax;
x=load('ww.txt');
tmax= length(x) ;
tt= 0:tmax -1;
x4 = x(1:5:end);
t1_n = 1:5:tt;
x1_n_ref=0;
k=0;
for i=1:length(x4)
if x4(i)>170
if x1_n_ref-x4(i)<0
x1_n_ref=x4(i);
alpha=1;
elseif alpha==1 && x1_n_ref-x4(i)>0
k=k+1;
peak(k)=x1_n_ref; // This is my peak value. but I also want to know the index of it. which will represent the time.
%peak_time(k) = t1_n(i); // this is my issue.
alpha=2;
end
else
x1_n_ref=0;
end
end
%----------------------
figure(1)
% plot(t,x,'k','linewidth',2)
hold on
% subplot(2,1,1)
grid
plot( x4,'b'); % ,tt,x,'k'
legend('down-sampling by 5');
Here is you error:
tmax= length(x) ;
tt= 0:tmax -1;
x4 = x(1:5:end);
t1_n = 1:5:tt; % <---
tt is an array containing numbers 0 through tmax-1. Defining t1_n as t1_n = 1:5:tt will not create an array, but an empty matrix. Why? Expression t1_n = 1:5:tt will use only the first value of array tt, hence reduce to t1_n = 1:5:tt = 1:5:0 = <empty matrix>. Naturally, when you later on try to access t1_n as if it were an array (peak_time(k) = t1_n(i)), you'll get an error.
You probably want to exchange t1_n = 1:5:tt with
t1_n = 1:5:tmax;
You need to index the tt array correctly.
you can use
t1_n = tt(1:5:end); % note that this will give a zero based index, rather than a 1 based index, due to t1_n starting at 0. you can use t1_n = 1:tmax if you want 1 based (matlab style)
you can also cut down the code a little, there are some variables that dont seem to be used, or may not be necessary -- including the t1_n variable:
x=load('ww.txt');
tmax= length(x);
x4 = x(1:5:end);
xmin = 170
% now change the code
maxnopeaks = round(tmax/2);
peaks(maxnopeaks)=0; % preallocate the peaks for speed
index(maxnopeaks)=0; % preallocate index for speed
i = 0;
for n = 2 : tmax-1
if x(n) > xmin
if x(n) >= x(n-1) & x(n) >= x(n+1)
i = i+1;
peaks(i) = t(n);
index(i) = n;
end
end
end
% now trim the excess values (if any)
peaks = peaks(1:i);
index = index(1:i);

Trying to understand how to iterate over more-dim Arrays

I am trying to learn how to iterate over arrays and therefore made up my own scenarios to practise on.
Let's say my given matrix is a two-dimensional, therefore an two-dim. Array.
mat =[[1,2,300,-400],[0,3,-1,9],[3,4,-5,1]]
Task 1) Return the Array with the highest sum of the values.
Task 2) Given that this Array could produce a nxm matrix, return the value of the row and column for which the sum of the enclosing number is the highest.
To make it easier to understand let us use a different matrix here.
mat= [[1,1,1,1],[2,2,2,2],[3,3,3,3],[4,4,4,4]]
So it would look like this:
1111
2222
3333
4444
And the result would be [2,1] or [2,2]
since the sum for those numbers (2+2+2+3+3+4+4+4) = 24 would be the highest.
Here are my implementations so far:
Task 1)
I only can solve this with adding a sum function to the class Array.
def max_row(mat)
return mat.max{|a,b| a.sum <=> b.sum }
end
class Array
def sum
sum = 0
self.each(){|x|
sum += x
}
return sum
end
end
I do want to solve it without using an extra method so, but I do not know how to.
my idea so far :
def max_row(mat)
sum_ary = []
mat.each(){|ary|
sum = 0
ary.each(){|x|
sum += x
}
sum_ary << [sum]
}
I tried find_index on my sum_ary, but as implemented it returns the first value which is not false, therefore I cannot use it to search for the biggest value.
Implementation Task 2):
mat = [[1,1,1,1],[2,2,2,2],[3,3,3,3],[4,4,4,4]]
def max_neighbor_sum(mat)
sum_result = []
for n in 0...mat.size()
for m in 0...mat.size()
sum = 0
for a in (n-1)..(n+1)
for b in (m-1)..(m+1)
if m != nil && n !=nil && a>=0 && b>=0 && a<= (mat.size()-1)
# print "n:#{n} m:#{m} a:#{a} b:#{b} \n"
# p mat[a][b]
if mat[a][b] !=nil && !(n==a && m==b)
sum += mat[a][b]
end
end
end
end
sum_result << sum
# p sum_result
end
end
return sum_result
end
I calculated all the sums correctly, but have no idea how I get the index for the row and column now.
I hope you can understand where I need some help.
Problem 1:
arrays.map(&:sum).max
Calls sum for each of the arrays, then chooses the biggest of them
Problem 2 can't be solved so easily, but this should work:
max_sum = 0
max_index = []
for n in 0...mat.size
for m in 0...mat.size
sum = 0
for a in (n-1)..(n+1)
for b in (m-1)..(m+1)
sum += mat[a][b] unless mat[a].nil? || mat[a][b].nil?
end
end
if sum > max_sum
max_sum = sum
max_index = [n,m]
end
end
end
max_sum # => maximum sum of all neighbours
max_index # => a pair of indexes which have the max sum
If you want to keep all of max indexes, just replace it with an array of pairs and push if the sum is equal to max_sum.
Here is my solution to task 2 which I came up with thanks to Piotr Kruczek.
Thanks for the kind help!
def max_neighbour_sum(mat)
sum_result = []
max_sum = 0
for n in 0...mat.size()
for m in 0...mat.size()
sum = 0
for a in (n-1)..(n+1)
for b in (m-1)..(m+1)
if m != nil && n !=nil && a>=0 && b>=0 && a<= (mat.size()-1)
# print "n:#{n} m:#{m} a:#{a} b:#{b} \n"
# p mat[a][b]
if mat[a][b] !=nil && !(n==a && m==b)
sum += mat[a][b]
end
end
end
end
if sum > max_sum
max_sum = sum
sum_result = [n,m]
end
# p sum_result
end
end
return sum_result
end

Resources