Summing specific fields in Matlab - matlab

How do I sum different fields? I want to sum all of the information for material(1) ...so I want to add 5+4+6+300 but I am unsure how. Like is there another way besides just doing material(1).May + material(1).June etc....
material(1).May= 5;
material(1).June=4;
material(1).July=6;
material(1).price=300;
material(2).May=10;
material(2).price=550;
material(3).May=90;

You can use structfun for this:
result = sum( structfun(#(x)x, material(1)) );
The inner portion (structfun(#(x)x, material(1))) runs a function each individual field in the structure, and returns the results in an array. By using the identity function (#(x)x) we just get the values. sum of course does the obvious thing.
A slightly longer way to do this is to access each field in a loop. For example:
fNames = fieldnames(material(1));
accumulatedValue = 0;
for ix = 1:length(fNames)
accumulatedValue = accumulatedValue + material(1).(fNames{ix});
end
result = accumulatedValue
For some users this will be easier to read, although for expert users the first will be easier to read. The result and (approximate) performance are the same.

I think Pursuit's answer is very good, but here is an alternative off the top of my head:
sum( cell2mat( struct2cell( material(1) )));

Related

Most efficient way to store dictionaries in Matlab

I have a set of IDs associated with costs which is just a double value. IDs are integers and unique. Two IDs may have same costs. I stored them as:-
a=containers.Map('KeyType','uint32','ValueType','double');
a(1)=7.3
a(2)=8.4
a(3)=7.3
Now i want to find the minimum cost.
b=[];
c=values(a);
b=[b,c{:}];
cost_min=min(b);
Now i want to find all IDs associated i.e. 1 and 3 with the minimum cost i.e. 7.3. I can collect all the keys into an array and then do a for loop over this array. Is there a better way to do this entire thing in Matlab so that for loops are not required?
sparse matrix can work as a hashmap, just do this:
a= sparse(1:3,1,[7.3 8.4 7.3])
find(a == min(nonzeros(a))
There are methods which can be used on maps for this kind of operations
http://se.mathworks.com/help/matlab/ref/containers.map-class.html
The approach finding minimum values and minimum keys can be done something like this,
a=containers.Map('KeyType','uint32','ValueType','double');
a(1)=7.3;
a(3)=8.4;
a(4)=7.3;
minval = inf;
minkeys = -1;
for k = keys(a)
val = a.values(k);
val = val{1};
if (val < minval(1))
minkeys = k;
minval = val;
elseif (val == minval(1))
minkeys = [minkeys,k];
end
end
disp(minval);
disp(minkeys);
This is not efficient though and value search is clumsy for maps. This is not what they are intended for. Maps is supposed to do efficient key lookup. In case you are going to do a lot of lookups and this is what takes time, then use a map. If you need to do a lot of value searches, I would recommend that you use a matrix (or two arrays) for this instead.
idx = [1;3;4];
val = [7.3,8.3,7.3];
minval = min(val);
minidx = idx(val==minval);
disp(minval);
disp(minidx);
There is also another post with an example where it is shown how a sparse matrix can be used as a hashmap. Let the index become the key. This will take about 3 times the memory as all non-zero elements an ordinary array, but a map uses more memory than an array as well.

How to filter and save each variable on matlab

I have a data (matrix) with 3 columns : DATA=[ID , DATE, Value]
I want to filter my data by ID for example DATAid1= DATA where ID==1 and so on ..
for that I write this code in MATLAB
load calibrage_capteur.mat
data = [ID ,DATE , Valeur]
minid = min(data(:,1));
maxid = max(data(:,1));
for i=minid:maxid
ind=find(data(:,1) == i)
dataID = [ID(ind) ,DATE(ind) , Valeur(ind)]
end
As a result he register the last value in this example the max ID=31 so he register dataId31. Now I need how to save the variable each iteration. How can I do this?
You will want to use a cell array to hold your data rather than saving them as independent variables that are named based upon the ID.
data_by_ID = cell();
ids = minid:maxid;
for k = 1:numel(ids)
data_by_ID{k} = data(data(:,1) == ids(k),:);
end
Really though, depending on what you're doing with it, you can use data all of the time since all operations are going to be faster on a numeric matrix than they are on a cell array.
%// Do stuff with data ID = 10
do_stuff(data(data(:,1) == 10, :));
Update
If you absolutely must name your variables you could do the following (but please don't do this and use one of the methods above).
for k = 1:numel(ids)
eval(['dataId', num2str(ids(k)), '= data(k,:);']);
end
Your question is a bit unclear but it sounds like you simply want to save the result at each iteration of the for loop.
I'm assuming min and max id are arbitrary and not necessarily the variable you are trying to index on.
kk = min_id:max_id;
dataID=nan(size(kk));
for ii = 1:numel(kk)
ind=find(data(:,1) == kk(ii))
dataID(kk) = [ID(ind) ,DATE(ind) , Valeur(ind)]
end
This is better than indexing by min_id or max_id since it isn't clear that min_id starts at at 1 (maybe it starts at 0, or something else.)

Find value in vector "p" that corresponds to maximum value in vector "r = f(p)"

As simple as in title. I have nx1 sized vector p. I'm interested in the maximum value of r = p/foo - floor(p/foo), with foo being a scalar, so I just call:
max_value = max(p/foo-floor(p/foo))
How can I get which value of p gave out max_value?
I thought about calling:
[max_value, max_index] = max(p/foo-floor(p/foo))
but soon I realised that max_index is pretty useless. I'm sorry asking this, real beginner here.
Having dropped the issue to pieces, I realized there's no unique corrispondence between values p and values in my related vector p/foo-floor(p/foo), so there's a logical issue rather than a language one.
However, given my input data, I know that the solution is unique. How can I fix this?
I ended up doing:
result = p(p/foo-floor(p/foo) == max(p/foo-floor(p/foo)))
Looks terrible, so if you know any other way...
Once you have the index, use it:
result = p(max_index)
You can create a new vector with your lets say "transformed" values:
p2 = (p/foo-floor(p/foo))
and then just use find to find the max values on p2:
max_index = find(p2 == max(p2))
that will return the index or indices of p2 with the max value of that operation, and finally just lookup the original value in p
p(max_index)
in 1 line, this is:
p(find((p/foo-floor(p/foo) == max((p/foo-floor(p/foo))))))
which is basically the same thing you did in the end :)

How to minimize Sum in Maple

I have the following problem - I need to minimize the sum in the maple. For example, suppose I have this:
EXPESSION:=A[0]+A[1]+A[2]+A[3]+A[4]+A[5];
And I want to use some function
someFunction(EXPRESSION);
which will return a symbol of the Sum (like sum(A[i], i = 0 .. 5));
Is some function like that exists?
Okay, I guess that you need something to compress an existing expession. If you're willing to specify the summand, index, and index range, then someFunction could subtract the terms and add the (unevaluated) Sum of those terms.
convert_to_Sum:= (ex, summand, index)->
simplify(ex - sum(summand, index) + Sum(summand, index))
;
Example:
ex:= A[0]+A[1]+A[2]+A[3]+A[4]+A[5];
convert_to_Sum(ex, A[i], i= 0..5);
Use Sum(A[i], i= 0..5)
Note that Sum is uppercase. I realize that this does not handle the case where the expression already exists, which may be what you are primarily interested in.

Complementary array Matlab

We've got an array of values, and we would like to create another array whose values are not in the first one.
Example:
load('internet.mat')
The first column contains the values in MBs, we have thought in something like:
MB_no = setdiff(v, internet(:,1))
where v is a 0 vector whose length equals to the number of rows in internet.mat. But it just doesn't work.
So, how do we do this?
You need to specify the range of possible values to define what values are not in internet . Say the range is v = 1:10 then setdiff(v,internet(:,1)) will give you the values in 1:10 that are not in the first column of internet.
It seems as if you don't want the first column.
You can simply do:
MB_no=internet(:,2:end);
assuming internet(:,1) has only positive integers and you wish to find which are the integers in [1,...,max( internet(:,1) )] that do not appear in that range you can simply do
app = [];
app( internet(:,1) ) = 1;
MB_no = find( app == 0 );
This is somewhat like bucket sort.