Standard ML : How to access column from list of list in standard ML - ml

Suppose I have a list of list
list = [[1,2,3],[4,5,6],[7,8,9]]
and i want to calculate the sum of the columns.
i.e The first column is [1,4,7]and its sum is 12
Second column is [2,5,8] ans sum is 15 and so on
Is there any efficient way(with less complexity) in standard ML to do this?? Please help

For example:
fun transpose [] = []
| transpose ([]::xss) = []
| transpose xss = map hd xss :: transpose (map tl xss)
val sum = foldl op+ 0
val sumsOfColumns = map sum o transpose
Example use:
sumsOfColumns [[1,2,3],[4,5,6],[7,8,9]] (* => [12, 15, 18] *)
;)

Related

Fast way to store different length Matrix rows into Cell

I have three matrices:
Values = [200x7] doubles
numOfStrings = [82 78 75 73 72 71 70] %(for example)
numOfColumns = [1 4]
The numOfColumns may contain any set of distinct values from 1 to 7. For example [1 2 3] or [4 7] or [1 5 6 7]. Obviously, biggest numOfColumns that can be is [1 2 3 4 5 6 7].
numOfColumns show the columns I want to get. numOfStrings shows the rows of that columns I need. I.e. in my example I want to get columns 1 and 4. So from the 1 column I want to get the 82 first rows and from the 4th get the 73 first rows.
i.e. if numOfColumns = [1 4] then
myCell{1} = Values( 1:82,1); % Values(numOfStrings(numOfColumn(1)), numOfColumn(1))
myCell{2} = Values( 1:73,4); % Values(numOfStrings(numOfColumn(2)), numOfColumn(2))
P.S. That's not necessary to save it into cell array. If you can offer any another solution Ill be grateful to you.
I'm looking for the fastest way to do this, which is likely to be by avoiding for loops and using vectorization.
I think a lot about sub2ind function. But I can't figure out how to return arrays of the different size! Because myCell{1} - [82x1] and myCell{2} - [73x1]. I suppose I can't use bsxfun or arrayfun.
RESULTS:
Using for loops alike #Will 's answer:
for jj = 1:numel(numOfColumns)
myCell{rowNumber(numOfColumns(jj)),numOfColumns(jj)} = Values( 1:numOfStrings(numOfColumns(jj)),numOfColumns(jj));
end
Elapsed time is 157 seconds
Using arrayfun alike #Yishai E 's answer:
myCell(sub2ind(size(myCell),rowNumber(numOfColumns),numOfColumns)) = arrayfun( #(nOC) Values( 1:numOfStrings(nOC),nOC), numOfColumns, 'UniformOutput', false);
Elapsed time is 179 seconds
Using bsxfun alike #rahnema1 's answer:
idx = bsxfun(#ge,numOfStrings , (1:200).');
extracted_values = Values (idx);
tempCell = mat2cell(extracted_values,numOfStrings);
myCell(sub2ind(size(myCell),rowNumber(numOfColumns),numOfColumns)) = myCell(numOfColumns)';
Elapsed time is 204 seconds
SO, I got a lot of working answers, and some of them are vectorized as I asked, but for loops still fastest!
This should solve your problem, using arrayfun, which "vectorizes" the application of the indexing function. Not really, but it doesn't call the interpreter for each entry from numOfColumns. Interestingly enough, this is slower than the non-vectorized code in the other answer! (for 1e5 entries, 0.95 seconds vs. 0.23 seconds...)
arrayfun(#(nOC)Values(1:numOfStrings(nOC), nOC), numOfColumns, 'UniformOutput', false)
% Get number of elements in NUMOFCOLUMNS
n = numel(numOfColumns);
% Set up output
myCell = cell(1,n);
% Loop through all NUMOFCOLUMNS values, storing to cell
for i = 1:n
myCell{i} = Values(1:numOfStrings(numOfColumns(i)), numOfColumns(i));
end
Which for your example gives output
myCell =
[82x1 double] [73x1 double]
You can create logical indices for extraction of the desired elements :
idx = bsxfun(#ge,numOfStrings , (1:200).');
that in MATLAB R2016b or Octave (thanks to broadcasting/expansion) can be written as:
idx = numOfStrings >= (1:200).';
extract values:
extracted_values = Values (idx);
then using mat2cell convert data to cell :
myCell = mat2cell(extracted_values,numOfStrings);
all in one line :
myCell = mat2cell(Values (numOfStrings >= (1:200).'), numOfStrings);
If you want to use different numOfColumns with different sizes to extract elements of the cell you can each time do this:
result = myCell(numOfColumns);
If both numOfStrings and numOfColumns change and you need to compute the result once do this:
%convert numOfColumns to logical index:
numcols_logical = false(1,7);
numcols_logical(numOfColumns) = true;
extracted_values = Values ((numOfStrings .* numcols_logical) >= (1:200).');
if you need cell array
result= mat2cell(extracted_values,numOfStrings(numcols_logical));

Intersection of multiple arrays without for loop in MATLAB

I've always been told that almost all for loops can be omitted in MATLAB and that they in general slow down the process. So is there a way to do so here?:
I have a cell-array (tsCell). tsCell stores time-arrays with varying length. I want to find an intersecting time-array for all time-arrays (InterSection):
InterSection = tsCell{1}.time
for i = 2:length{tsCell};
InterSection = intersect(InterSection,tsCell{i}.time);
end
Here's another way. This also assumes there are no duplicates within each original vector.
tsCell_time = {[1 6 4 5] [4 7 1] [1 4 3] [4 3 1 7]}; %// example data (from Divakar)
t = [tsCell_time{:}]; %// concat into a single vector
u = unique(t); %// get unique elements
ind = sum(bsxfun(#eq, t(:), u), 1)==numel(tsCell_time); %// indices of unique elements
%// that appear maximum number of times
result = u(ind); %// output those elements
Here's a vectorized approach using unique and accumarray, assuming there are no duplicates within each cell of the input cell array -
[~,~,idx] = unique([tsCell_time{:}],'stable')
out = tsCell_time{1}(accumarray(idx,1) == length(tsCell_time))
Sample run -
>> tsCell_time = {[1 6 4 5],[4 7 1],[1 4 3],[4 3 1 7]};
>> InterSection = tsCell_time{1};
for i = 2:length(tsCell_time)
InterSection = intersect(InterSection,tsCell_time{i});
end
>> InterSection
InterSection =
1 4
>> [~,~,idx] = unique([tsCell_time{:}],'stable');
out = tsCell_time{1}(accumarray(idx,1) == length(tsCell_time));
>> out
out =
1 4

Correct usage of arrayfun/bsxfun in Matlab - simple example

Assume we have a 1-d Matrix, with random length:
M = [102,4,12,6,8,3,4,65,23,43,111,4]
Moreover I have a vector with values that are linked to the index of M:
V = [1,5]
What i want is a simple code of:
counter = 1;
NewM = zeros(length(V)*3,1);
for i = 1:length(V)
NewM(counter:(counter+2)) = M(V(i):(V(i)+2))
counter = counter+3;
end
So, the result will be
NewM = [102,4,12,8,3,4]
In other words, I want the V to V+2 values from M in a new array.
I'm pretty sure this can be done easier, but I'm struggeling with how to implement it in arrayfun /bsxfun...
bsxfun(#(x,y) x(y:(y+2)),M,V)
With bsxfun it's about getting the Vi on one dimension and the +0, +1 +2 on the other:
M = [102,4,12,6,8,3,4,65,23,43,111,4];
V = [1,5];
NewM = M( bsxfun(#plus, V(:), 0:2) )
NewM =
102 4 12
8 3 4
Or if you want a line:
NewM = reshape(NewM.', 1, [])
NewM =
102 4 12 8 3 4
Using arrayfun (note that M is used as an "external" matrix entity in this scope, whereas the arrayfun anonymous function parameter x correspond to the elements in V)
NewM = cell2mat(arrayfun(#(x) M(x:x+2), V, 'UniformOutput', false));
With result
NewM =
102 4 12 8 3 4
One fully vectorized solution is to expand V to create the correct indexing vector. In your case:
[1,2,3,5,6,7]
You can expand V to replicate each of it's elements n times and then add a repeating vector of 0:(n-1):
n = 3;
idx = kron(V, ones(1,n)) + mod(0:numel(V)*n-1,n)
So here kron(V, ones(1,n)) will return [1,1,1,5,5,5] and mod(0:numel(V)*n-1,n) will return [0,1,2,0,1,2] which add up to the required indexing vector [1,2,3,5,6,7]
and now it's just
M(idx)
Note a slightly faster alternative to kron is reshape(repmat(V,n,1),1,[])

Vectorize 3d operation in matlab

Can you vectorize a operation where the columns of U are added to cwx and the result is stored in a 3d array?
A non-vectorized solution:
cwx =rand([500,100]);
U = rand([500 10]);
F = zeros([500 100 10]);
for y = 1:10
F(:,:,y) = bsxfun(#plus,U(:,y),cwx);
end
It can be done with a single call to bsxfun, provided you first permute the second and third dimensions of U:
F = bsxfun(#plus, permute(U, [1 3 2]), cwx);

Selecting elements from an array in MATLAB

I know that in MATLAB, in the 1D case, you can select elements with indexing such as a([1 5 3]), to return the 1st, 5th, and 3rd elements of a. I have a 2D array, and would like to select out individual elements according to a set of tuples I have. So I may want to get a(1,3), a(1,4), a(2,5) and so on. Currently the best I have is diag(a(tuples(:,1), tuples(:,2)), but this requires a prohibitive amount of memory for larger a and/or tuples. Do I have to convert these tuples into linear indices, or is there a cleaner way of accomplishing what I want without taking so much memory?
Converting to linear indices seems like a legitimate way to go:
indices = tuples(:, 1) + size(a,1)*(tuples(:,2)-1);
selection = a(indices);
Note that this is also implement in the Matlab built-in solution sub2ind, as in nate'2 answer:
a(sub2ind(size(a), tuples(:,1),tuples(:,2)))
however,
a = rand(50);
tuples = [1,1; 1,4; 2,5];
start = tic;
for ii = 1:1e4
indices = tuples(:,1) + size(a,1)*(tuples(:,2)-1); end
time1 = toc(start);
start = tic;
for ii = 1:1e4
sub2ind(size(a),tuples(:,1),tuples(:,2)); end
time2 = toc(start);
round(time2/time1)
which gives
ans =
38
so although sub2ind is easier on the eyes, it's also ~40 times slower. If you have to do this operation often, choose the method above. Otherwise, use sub2ind to improve readability.
if x and y are vectors of the x y values of matrix a, then sub2und should solve your problem:
a(sub2ind(size(a),x,y))
For example
a=magic(3)
a =
8 1 6
3 5 7
4 9 2
x = [3 1];
y = [1 2];
a(sub2ind(size(a),x,y))
ans =
4 1
you can reference the 2D matlab position with a 1D number as in:
a = [3 4 5;
6 7 8;
9 10 11;];
a(1) = 3;
a(2) = 6;
a(6) = 10;
So if you can get the positions in a matrix like this:
a([(col1-1)*(rowMax)+row1, (col2-1)*(rowMax)+row2, (col3-1)*(rowMax)+row3])
note: rowmax is 3 in this case
will give you a list of the elements at col1/row1 col2/row2 and col3/row3.
so if
row1 = col1 = 1
row2 = col2 = 2
row3 = col3 = 3
you will get:
[3, 7, 11]
back.

Resources