Print specific parts of a cell as strings in matlab? - arrays

I have the following matrix array B :
B=[1 2 3; 10 20 30 ; 100 200 300 ; 500 600 800];
Which through a code is combined to form possible combinations between the values. The results are stored in cell G. Such that G :
G=
[1;20;100;500]
[0;30;0;800]
[3;0;0;600]
.
.
etc
I want to format the results based on which value from B is chosen :
[1 2 3] = 'a=1 a=2 a=3'
[10 20 30] = 'b=1 b=2 b=3'
[100 200 300]= 'c=1 c=2 c=3'
[500 600 800]= 'd=1 d=2 d=3'
Example, using the results in the current cell provided :
[1;20;100;500]
[0;30;0;800]
[3;0;0;600]
Should print as
a=1 & b=2 & c=1 & d=1
a=0 & b=3 & c=0 & d=3 % notice that 0 should be printed although not present in B
a=3 & b=0 & c=0 & d=2
Note that the cell G will vary depending on the code and is not fixed. The code used to generate the results can be viewed here : Need help debugging this code in Matlab
Please let me know if you require more info about this.

You can try this:
k = 1; % which row of G
string = sprintf('a = %d, b = %d, c = %d, d = %d',...
max([0 find(B(1,:) == G{k}(1))]), ...
max([0 find(B(2,:) == G{k}(2))]), ...
max([0 find(B(3,:) == G{k}(3))]), ...
max([0 find(B(4,:) == G{k}(4))]) ...
);
For instance, for k = 1 of your example data this results in
string =
a = 1, b = 2, c = 1, d = 1
A short explanation of this code (as requested in the comments) is as follows. For the sake of simplicity, the example is limited to the first value of G and the first line of B.
% searches whether the first element in G can be found in the first row of B
% if yes, the index is returned
idx = find(B(1,:) == G{k}(1));
% if the element was not found, the function find returns an empty element. To print
% a 0 in these cases, we perform max() as a "bogus" operation on the results of
% find() and 0. If idx is empty, it returns 0, if idx is not empty, it returns
% the results of find().
val = max([0 idx])
% this value val is now formatted to a string using sprintf
string = sprintf('a = %d', val);

Related

apply sum along subsets of array 3rd dimension

I have the following objects:
A: 1 array with x,y,z, dimensions -> containing a variable (Temperature)
B & C: 2 arrays with x,y dimensions -> containing the indices of vectors along A's z dimension
A <- array(rnorm(n = 12*4*3*5), dim = c(4,3,5))
dimnames(A) <- list("x" = c(1:4), "y" = c(1:3), "z" = c(1:5))
B <- matrix(rep(c(2:1), 6), nrow = 4)
dimnames(B) <- list("x" = c(1:4), "y" = c(1:3))
C <- matrix(rep(c(4:5), 6), nrow = 4)
dimnames(C) <- list("x" = c(1:4), "y" = c(1:3))
I'm looking for a way to apply sum of A across the z dimension only between the indices indicated by B and C.
If instead of the 3D-array I had a vector I would solve it like this:
> A <- round(c(rnorm(5)), 1)
> B <- 2 #index of first value to sum
> C <- 4 #index of last value to sum
> vindex <- seq(B,C,1)
> A
[1] 0.0 -0.9 -1.1 -1.7 -0.4
> vindex
[1] 2 3 4
> sum(A[vindex])
[1] -3.7
>
# or better with a function
> foo <- function(x, start_idx, end_idx) {
+ vidx <- seq(start_idx, end_idx, 1)
+ return(sum(x[vidx]))
+ }
>
> foo(A,B,C)
[1] -3.7
Unfortunately seq() does not accept vectors as arguments and therefore it's not straightforward to use the apply function. If again were A[x,y,z] and B and C[x,y]:
> apply(A,c(1,2),foo,B,C)
Error in seq.default(start_idx, end_idx, 1) : 'from' must be of length 1
Called from: seq.default(start_idx, end_idx, 1)
It would be great if anybody knew how to make this function workable with apply or with other clean solutions.
Thanks a lot!
This is not a very nice task for base R, and I would prefer to implement it in C++ in the absence of a package that already does so (?).
Logically speaking, a plain but vectorized solution to your problem could be structured as:
# initialize index array
D <- array(
1,
dim = c(4,3,5),
dimnames = list(x = letters[1:4], y = letters[1:3], z = letters[1:5])
)
# set indices out of bounds to zero
E <- rep(1:5, each = 4*3)
BB <- rep(B, times = 5)
D[E < BB] <- 0
CC <- rep(C, times = 5)
D[E > CC] <- 0
# multiply with index array and sum
apply(A * D, c(1,2), sum)

Error while increasing array value size by 1 error

I'm trying to create a program that will take an input of two integers of size 10 and below, that counts the amount of carry operations as a result of summing the input integers.
For example:
Sample Input:
59864417 974709147
Sample Output:
6
The line which returns an error in my program is:
parta[i+1] = ( parta[i+1] + 1 )
There i'm trying to add 1 to the value currently in the next array position.
run = true
while run == true
#input string
text = gets.chomp
#split string and remove space
parta = text.split[0]
partb = text.split[1]
#convert split strings to integers
partf1 = parta.to_i
partf2 = partb.to_i
#check for terminal input of 0
if partf1 + partf2 <= 0
run = false
end
#fill strings with 0s to size 11
parta = sprintf( "%011i", parta )
partb = sprintf( "%011i", partb )
#convert strings to arrays of integers
parta = parta.split("").map(&:to_i)
partb = partb.split("").map(&:to_i)
count = 0
(10).downto(0) do |i|
if ( parta[i] + partb[i] ) > 9
count = count + 1
parta[i+1] = ( parta[i+1] + 1 )
#59864417 974709147 test input should output 6
end
end
if run == true
puts "#{count} carry operations."
end
end
When I run I get the following error message:
test5.ruby:42:in block in <main>': undefined method+' for nil:NilClass (NoMethodError)
from test5.ruby:29:in downto'
from test5.ruby:29:in
Could anyone help me? :)
Expanding my comment into a slightly longer answer:
I suspect there's a simpler approach overall, but for your particular issue: the highest index in the array is 10. In that case, when i is 10, parta[i+1] (on the right side) is nil, because there's no element in the array with that index. When you try to increment nil, you get an error. But it should be parta[i-1] = parta[i-1] + 1 anyway if you're trying to go from right to left. This will cause some odd behavior when i is 0, but you might not care about that.
The problem is on this line
parta[i+1] = ( parta[i+1] + 1 )
In case i == size of the array the expression i + 1 will return nil which causes the error.
Just for fun, here's the rewritten version with Ruby 2.4 (for Intger#digits):
a = 59_864_417
b = 974_709_147
a, b = [a, b].sort
carry = false
count = b.digits.zip(a.digits).count do |m, n|
r = m + (n || 0) + (carry ? 1 : 0)
carry = r > 9
end
p count
#=> 6

Count items in one cell array in another cell array matlab

I have 2 cell arrays which are "celldata" and "data" . Both of them store strings inside. Now I would like to check each element in "celldata" whether in "data" or not? For example, celldata = {'AB'; 'BE'; 'BC'} and data={'ABCD' 'BCDE' 'ACBE' 'ADEBC '}. I would like the expected output will be s=3 and v= 1 for AB, s=2 and v=2 for BE, s=2 and v=2 for BC, because I just need to count the sequence of the string in 'celldata'
The code I wrote is shown below. Any help would be certainly appreciated.
My code:
s=0; support counter
v=0; violate counter
SV=[]; % array to store the support
VV=[]; % array to store the violate
pairs = ['AB'; 'BE'; 'BC']
%celldata = cellstr(pairs)
celldata = {'AB'; 'BE'; 'BC'}
data={'ABCD' 'BCDE' 'ACBE' 'ADEBC '} % 3 AB, 2 BE, 2 BC
for jj=1:length(data)
for kk=1:length(celldata)
res = regexp( data(jj),celldata(kk) )
m = cell2mat(res);
e=isempty(m) % check res array is empty or not
if e == 0
s = s + 1;
SV(jj)=s;
v=v;
else
s=s;
v= v+1;
VV(jj)=v;
end
end
end
If I am understanding your variables correctly, s is the number of cells which the substring AB, AE and, BC does not appear and v is the number of times it does. If this is accurate then
v = cellfun(#(x) length(cell2mat(strfind(data, x))), celldata);
s = numel(data) - v;
gives
v = [1;1;3];
s = [3;3;1];

Signal created with matlab function block in simulink

I want to generate an arbitrary linear signal from matlab function block in simulink. I have to use this block because then, I want to control when i generate the signal by a sequence in Stateflow. I try to put the out of function as a structure with a value field and another time as the following code:
`function y = sig (u)
if u == 1
t = ([0 10 20 30 40 50 60]);
T = [(20 20 40 40 60 60 0]);
S.time = [t '];
S.signals (1) values ​​= [T '].;
S.signals (1) = 1 dimensions.;
else
N = ([0 0 0 0 0 0 0]);
S.signals (1) values ​​= [N '].;
end
y = S.signals (1). values
end `
the idea is that u == 1 generates the signal, u == 0 generates a zero output.
I also try to put the output as an array of two columns (one time and another function value) with the following code:
function y = sig (u)
if u == 1
S = ([0, 0]);
cant = input ('Number of points');
for n = Drange (1: cant)
S (n, 1) = input ('time');
S (n, 2) = input ('temperature');  
end
y = [S]
else
y = [0]
end
end
In both cases I can not generate the signal.
In the first case I get errors like:
This structure does not have a field 'signals'; new fields can not be added When structure has-been read or used
or
Error in port widths or dimensions. Output port 1 of 'tempstrcutsf2/MATLAB Function / u' is a one dimensional vector with 1 elements.
or
Undefined function or variable 'y'. The first assignment to a local variable Determines its class.
And in the second case:
Try and catch are not supported for code generation,
Errors occurred During parsing of MATLAB function 'MATLAB Function' (# 23)
Error in port widths or dimensions. Output port 1 of 'tempstrcutsf2/MATLAB Function / u' is a one dimensional vector with 1 elements.
I'll be very grateful for any contribution.
PD: sorry for my English xD
You have many mistakes in your code
you have to read more about arrays and structs in matlab
here S = ([0, 0]); you're declare an array with only two elements so the size will be static
There is no function called Drange in mtlab except if it's yours
See this example with strcuts and how they are created for you function
function y = sig(u)
if u == 1
%%getting fields size
cant = input ('Number of points\r\n');
%%create a structure of two fields
S = struct('time',zeros(1,cant),'temperature',zeros(1,cant));
for n =1:cant
S.time(n) = input (strcat([strcat(['time' num2str(n)]) '= ']));
S.temperature(n) = input (strcat([strcat(['temperature'...
num2str(n)]) '= ']));
end
%%assign output as cell of struct
y = {S} ;
else
y = 0 ;
end
end
to get result form y just use
s = y{1};
s.time;
s.temperature;
to convert result into 2d array
2dArray = [y{1}.time;y{1}.temperature];
Work with arrays
function y = sig(u)
if u == 1
cant = input ('Number of points\r\n');
S = [];
for n =1:cant
S(1,n) = input (strcat([strcat(['time' num2str(n)]) '= ']));
S(2,n) = input (strcat([strcat(['temperature'...
num2str(n)]) '= ']));
end
y = S;
else
y = 0 ;
end
end

R: Aggregate on Group 1 and NOT Group 2

I am trying to create two data sets, one which summarizes data by 2 groups which I have done using the following code:
x = rnorm(1:100)
g1 = sample(LETTERS[1:3], 100, replace = TRUE)
g2 = sample(LETTERS[24:26], 100, replace = TRUE)
aggregate(x, list(g1, g2), mean)
The second needs to summarize the data by the first group and NOT the second group.
If we consider the possible pairs from the previous example:
A - X B - X C - X
A - Y B - Y C - Y
A - Z B - Z C - Z
The second dataset should to summarize the data as the average of the outgroup.
A - not X
A - not Y
A - not Z etc.
Is there a way to manipulate aggregate functions in R to achieve this?
Or I also thought there could be dummy variable that could represent the data in this way, although I am unsure how it would look.
I have found this answer here:
R using aggregate to find a function (mean) for "all other"
I think this indicates that a dummy variable for each pairing is necessary. However if there is anyone who can offer a better or more efficient way that would be appreciated, as there are many pairings in the true data set.
Thanks in advance
First let us generate the data reproducibly (using set.seed):
# same as question but added set.seed for reproducibility
set.seed(123)
x = rnorm(1:100)
g1 = sample(LETTERS[1:3], 100, replace = TRUE)
g2 = sample(LETTERS[24:26], 100, replace = TRUE)
Now we have two solutions both of which use aggregate:
1) ave
# x equals the sums over the groups and n equals the counts
ag = cbind(aggregate(x, list(g1, g2), sum),
n = aggregate(x, list(g1, g2), length)[, 3])
ave.not <- function(x, g) ave(x, g, FUN = sum) - x
transform(ag,
x = NULL, # don't need x any more
n = NULL, # don't need n any more
mean = x/n,
mean.not = ave.not(x, Group.1) / ave.not(n, Group.1)
)
This gives:
Group.1 Group.2 mean mean.not
1 A X 0.3155084 -0.091898832
2 B X -0.1789730 0.332544353
3 C X 0.1976471 0.014282465
4 A Y -0.3644116 0.236706489
5 B Y 0.2452157 0.099240545
6 C Y -0.1630036 0.179833987
7 A Z 0.1579046 -0.009670734
8 B Z 0.4392794 0.033121335
9 C Z 0.1620209 0.033714943
To double check the first value under mean and under mean.not:
> mean(x[g1 == "A" & g2 == "X"])
[1] 0.3155084
> mean(x[g1 == "A" & g2 != "X"])
[1] -0.09189883
2) sapply Here is a second approach which gives the same answer:
ag <- aggregate(list(mean = x), list(g1, g2), mean)
f <- function(i) mean(x[g1 == ag$Group.1[i] & g2 != ag$Group.2[i]]))
ag$mean.not = sapply(1:nrow(ag), f)
ag
REVISED Revised based on comments by poster, added a second approach and also made some minor improvements.

Resources