Nested loops in Matlab - matlab

I am trying to create a program that uses nested loops. The inner loop should generate 10 random integers between 1 and 100 in each iteration and should continue to generate sets of 10 random numbers until two of the numbers fall in between 33 and 43. I want the outer loop to repeat 5 times.
Having trouble figuring out thanks

I haven't tested this, but it should be a starting point:
for ii = 1:5 % Repeat loop 5 times
value = 0;
while value == 0 % While loop, will keep going as long as that statement is satisfied
nums = randi([1 100], [1 10]); % Generate 10 random integers from 1 to 100
test_nums = ((nums > 33) & (nums < 43)); % Create a logical array which is 1 for nums between 33 and 43
Tot = sum(test_nums);
if Tot >= 2 % If the number of numbers between 33 and 43 is 2 or more, break the loop
value = 1;
end
end
disp(nums)
end
Is this what you're after?
Edit As I have now tested it. This is more or less exactly what you asked for, but it's really really slow. I'm not sure how it could be sped up as it's the while loop which is holding everything up, and I don't know how to improve it.
Edit 2 Now it works perfectly - hopefully it does exactly what you're after.

Related

Produce 6 different number by only use "randi" and some loops

I want to only use "randi" this function to produce the 6 different number randomly in matlab ,and the range of these 6 number is 1 ~ 12.
number=randi([1,12],1,6)
c=0;
for n=1:6%when "n" is 1 to 6
while c <= 6 %while c is less equal than 6,do the program below
c = c + 1; %c=c+1
if number(n) == number(c) %when the nth element is equal to cth element
number(n) = randi(12); %produce a random integer in the nth element
c = 0; %the reason why i set c=0 again is because i want to check again whether the new random integer is the same as cth element or not
end
end
end
final_number=number
but the result still show me like
1 "2" 6 11 "2" 3
5 "8" "8" 12 3 1
How do i improve my code to produce 6 different numbers.i don't want to always rely on the convenient matlab instruction too much,so my tags will also write c.hoping someone can help me to improve this
If you're trying to reproduce randsample (or randperm), why not just reproduce the algorithm MATLAB uses? (As far as we can tell...)
This is the Fisher-Yates shuffle. If you have a vector v, each iteration selects a random, previously unused element and puts it at the end of the unselected elements. If you do k iterations, the last k elements of the list are your random sample. If k equals the number of elements in v, you've shuffled the entire array.
function sample = fisher_yates_sample(v, k)
% Select k random elements without replacement from vector v
% if k == numel(v), this is simply a fisher-yates shuffle
for n = 0:k-1
randnum = randi(numel(v)-n); % choose from unused values
% swap elements v(end-n) and v(randnum)
v([end-n, randnum]) = v([randnum, end-n]);
end
sample = v(end-k+1:end);
end
Unlike MATLAB's version, mine requires a vector as input, so to get 6 random values in the range 1:12 you'd call the function like this:
>> fisher_yates_sample(1:12,6)
ans =
5 11 6 10 8 4
Since you're re-selecting single random numbers, when there is one occuring multiple times, why not just re-selecting all numbers at once?
% Initial selecting of random numbers.
number = randi([1, 12], 1, 6)
% While the amount of unique elements in numbers is less than 6:
while (numel(unique(number)) < 6)
% Re-select random numbers.
number = randi([1, 12], 1, 6)
end
And since you wrote, you specifically want to use the randi method, I guess there is a reason, you don't want to use randperm(12, 6)!?
What you are looking for is randperm. It produces a random permutation of a range of integers, so that if you select the first k numbers, you are sure that you get k unique integers in the range [1;n].
In your case, simply call:
randperm(12,6)

Matlab: How do I use two nested for-loops to generate a consecutive list of numbers in ascending order?

I would like to obtain an array of consecutive numbers from 1 to the product of the limits of two nested loops. I hope the example below will clarify the question. If I have the nested loop:
for i = 1:limit_loop_1
for j = 1:limit_loop_2
a = ???;
disp(a)
end
end
I would like to obtain a = (1:(limit_loop_1*limit_loop_2))'
For example, having:
for i = 1:3
for j = 1:5
a = ????;
disp(a)
end
end
I would like to get:
a=
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
I found similar questions for Java (like here), but nothing for Matlab. Thanks in advance.
Edit: I need this particular procedure because I will use the index to refer to another array. So, if I have for example a 3D array A of size (100,1,15) within the nested loops, I want to consider each one of the 15 elements of the array at each iteration. In code this would be:
for k = 1:100
for i = 1:3
for j = 1:5
something = A (k,1,????)
end
end
end
That is why ????? should go from 1 to 15. Hope this clarify my issue.
Obviously the solution you already provided (a = (1:(limit_loop_1*limit_loop_2))') is correct and absolutely nice. However if you must use a nested loop, just treat a as an external counter
a=0;
for i = 1:3
for j = 1:5
a = a+1;
disp(a)
end
end
This basically counts how many iteration are made by using the nested loop (3*5 in this case).
Or if you want to exploit the indices i and j you can re-adapt the Java example in Matlab by taking into account that in Matlab the indices start at 1 whereas in Java they start at 0:
for i = 1:3
for j = 1:5
c =1+(j-1)*1+(i-1)*(5);
disp(c)
end
end
I have no idea why you'd want to do it this way, but I'll take you at your word. This will give you the results you require:
for ii = 1:3
for jj = 1:5
a = 5*(ii-1)+jj;
disp(a)
end
end
(I changed your loop variables from i and j because they're the imaginary unit variables by default, and some folks get upset if you overwrite them.)
Results:
>> loop15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Save to array in for loop, with steps - Matlab

Okay, this is a bit tricky to explain, but I have a long .txt file with data (only one column). It could look like this:
data=[18
32
50
3
19
31
48
2
18
33
51
4]
Now, every fourth value (e.g. 18, 19, 18) represents the same physical quantity, just from different measurements. Now, I want Matlab to take every fourth value and put it into an array X=[18 19 18], and like wise for the other quantities.
My solution so far looks like this:
for i=1:3;
for j=1:4:12;
X(i)=data(j);
end
end
... in this example, because there are three of each quantity (therefore i=1:3), and there are 12 datapoints in total (therefore j=1:4:12, in steps of 4). data is simply the loaded list of datapoints (this works fine, I can test it in command window - e.g. data(2)=32).
My problem, doing this, is, that my array turns out like X=[18 18 18] - i.e. only the last iteration is put into the array
Of course, in the end, I would like to do it for all points; saving the 2nd, 6th, and 10th datapoint into Y and so on. But this is simply having more for-loops I guess.
I hope this question makes sense. I guess it is an easy problem to solve.
Why don't you just do?
>> X = data(1:4:end)
X =
18
19
18
>> Y = data(2:4:end)
Y =
32
31
33
You can reshape the data and then either split it up into different variables or just know that each column is a different variable (I'm now assuming each measurement occurs the same number of times i.e. length(data) is a multiple of 4)
data = reshape(data, 4, []).';
So now if you want
X = data(:,1);
Y = data(:,2);
%// etc...
But also you could just leave it as data all in one variable since calling data(:,1) is hardly more hassle than X.
Now, you should NOT use for-loops for this, but I'm gong to address what's wrong with your loops and how to solve this using loops purely as an explanation of the logic. You have a nested loop:
for i=1:3;
for j=1:4:12;
X(i)=data(j);
end
end
Now what you were hoping was that i and j would each move one iteration forward together. So when i==1 then j==1, when i==2 then j==5 etc but this is not what happens at all. To best understand what's going on I suggest you print out the variables at each iteration:
disp(sprintf('i: \tj:'));
for i=1:3;
for j=1:4:12;
disp(sprintf(' %d\t %d',i,j));
end
end
This prints out
i: j:
1 1
1 5
1 9
2 1
2 5
2 9
3 1
3 5
3 9
What you wanted was
disp(sprintf('i: \tj:'));
for i=1:3;
disp(sprintf(' %d\t %d',i,4*i-3));
end
which outputs:
i: j:
1 1
2 5
3 9
applied to your problem:
%// preallocation!
X = zeros(size(data,1)/4, 1)
for i=1:3
X(i)=data(i*4 - 3);
end
Or alternatively you can keep a separate count of either i or j:
%// preallocation!
X = zeros(size(data,1)/4, 1)
i = 1;
for j=1:4:end;
X(i)=data(j);
i = i+1;
end
Just for completeness your own solution should have read
i = 0;
for j=1:4:12;
i = i+1;
X(i)=data(j);
end
Of course am304's answer is a better way of doing it.

Determining probability of 4 of a kind in a 5 card poker hand Matlab

I am supposed to determine the probability of 4 of a kind in a 5 card poker draw using Matlab.
I understand the first thing I have to do is generate a deck and shuffle the cards, then draw 5 cards.
I am having trouble with determining whether the hand is 4 of a kind or not.
I have written the code below, which works for shuffling the deck and drawing 5 cards.
I have tried to use an if statement to determine if the hand is a 4 of a kind or not, but it does not work. My reasoning behind the if statement was that if I already had a sorted vector, the only two possibilities would be the first 4 or the last 4 numbers should all equal each other
Ex. AAAA_
_2222
Any advice on how to determine 4 of a kind would be very helpful :)
DECK = ['AH';'2H';'3H';'4H';'5H';'6H';'7H';'8H';'9H';'TH';'JH';'QH';'KH'; ...
'AS';'2S';'3S';'4S';'5S';'6S';'7S';'8S';'9S';'TS';'JS';'QS';'KS'; ...
'AD';'2D';'3D';'4D';'5D';'6D';'7D';'8D';'9D';'TD';'JD';'QD';'KD'; ...
'AC';'2C';'3C';'4C';'5C';'6C';'7C';'8C';'9C';'TC';'JC';'QC';'KC'];
%deck of 52 cards
total_runs=10000;
n=0;
for i=1:total_runs
index=randperm(52);
shuffle=DECK(index);
%shuffles the 52 columns
b=shuffle(1:5);
%chooses the first 5 cards
d=sort(b);
if d(1)==d(2)==d(3)==d(4)||d(2)==d(3)==d(4)==d(5)
%attempt to determine 4 of a kind
disp(d);
n=n+1;
end
end
prob=n/total_runs
You can't chain comparisons like that. You wrote:
d(1)==d(2)==d(3)==d(4)
But d(1) == d(2) evaluates to a logical, either true or false. That won't be equal to d(3).
Since they're sorted, you can just test
d(1)==d(4) || d(2)==d(5)
I was wracking my head about this for the last 30 minutes, and I began to wonder, why do we need to specify the suit? He can simply get a vector of [1 through 13 ...
1 through 13] with size 1x52 and use randperm(52,5). Or as follows:
DECK = [1 2 3 4 5 6 7 8 9 10 11 12 13 1 2 3 4 5 6 7 8 9 10 11 12 13 ...
1 2 3 4 5 6 7 8 9 10 11 12 13 1 2 3 4 5 6 7 8 9 10 11 12 13];
draw = randperm(52,5);
for k = 1:5;
hand(k) = DECK(draw(k));
end
Then you can check the first two indices of hand() and compare to hand; or:
for i=1:2
if sum(hand(i)==hand) == 4
n = n+1;
end
end
I think this way is short enough, though it would be more ideal to compare column or row values. This takes about 1 second to run N=100,000 iterations on an i5 5th gen. When I set it for 10 million iterations, I'm getting about 0.04% success, which is quite higher than the theoretical 0.02401%.
My first attempt comes out likes this:
hand = randperm(52,5);
for k=1:5
match = 0;
for i=1:3
if sum(hand(k)+13*i == hand) > 0
match = match+1;
end
end
if match == 3
four = four +1;
end
end
prob = four/N;
I like this one because I don't need to waste space with a large vector; however, it takes more processing power because of the 15 loops/more comparisons. I'm getting about 0.024% success over N=100,000 iterations for this one, which is almost on-the-dot with theory. The idea with the inner-most loop is that one of the cards in a four-of-a-kind will be equal to another card when you add 13*a to it, where a = 1,2,3. This method took me almost an hour to write since I was getting a little deep with the loops.
Please met me know of any concerns with the code, it's greatly appreciated.
edit: Haha I just realized that I am replicating results with my first script. Let's do it like this:
for i=1:2
if sum(hand(i)==hand) == 4
n = n+1;
end
end
should be:
if sum(hand(1)==hand) == 4
n = n+1;
elseif sum(hand(2)==hand) == 4
n = n+1;
end
something like that.
Thanks for posting an interesting question.
I somewhat find mixing strings and integers bit awkward to work with in MATLAB.
However this problem is solvable if we consider only integers from 1 to 52.
% 1 through 52
% ['AH';'2H';'3H';'4H';'5H';'6H';'7H';'8H';'9H';'TH';'JH';'QH';'KH'; ...
% 'AS';'2S';'3S';'4S';'5S';'6S';'7S';'8S';'9S';'TS';'JS';'QS';'KS'; ...
% 'AD';'2D';'3D';'4D';'5D';'6D';'7D';'8D';'9D';'TD';'JD';'QD';'KD'; ...
% 'AC';'2C';'3C';'4C';'5C';'6C';'7C';'8C';'9C';'TC';'JC';'QC';'KC'];
%deck of 52 cards . . from wikipedia
total_runs=2598960;
n=0;
for i=1:total_runs
index=randperm(52,5);
value = mod(index-1, 14);
if length(unique(value)) == 2
%attempt to determine 4 of a kind
n=n+1;
end
end
prob=n/total_runs
EDIT:
corrected to length(unique(value)) == 2
The probability that this gave is between 0.1% and 0.2%.Which seems reasonable.
However it should not be mod 13, because we want 13 distinct values for each color right .

find peak values in matlab

suppose that we are determine peaks in vector as follow:
we have real values one dimensional vector with length m,or
x(1),x(2),.....x(m)
if x(1)>x(2) then clearly for first point peak(1)=x(1);else we are then comparing x(3) to x(2),if x(3)
[ indexes,peaks]=function(x,m);
c=[];
b=[];
if x(1)>x(2)
peaks(1)=x(1);
else
for i=2:m-1
if x(i+1)< x(i) & x(i)>x(i-1)
peak(i)=x(i);
end;
end
end
end
peaks are determined also using following picture:
sorry for the second picture,maybe it is not triangle,just A and C are on straight line,but here peak is B,so i can't continue my code for writing algorithm to find peak values in my vector.please help me to continue it
updated.numercial example given
x=[2 1 3 5 4 7 6 8 9]
here because first point is more then second,so it means that peak(1)=2,then we are comparing 1 to 3,because 3 is more then 1,we now want to compare 5 to 3,it is also more,compare 5 to 4,because 5 is more then 4,then it means that peak(2)=5,,so if we continue next peak is 7,and final peak would be 9
in case of first element is less then second,then we are comparing second element to third one,if second is more then third and first elements at the same time,then peak is second,and so on
You could try something like this:
function [peaks,peak_indices] = find_peaks(row_vector)
A = [min(row_vector)-1 row_vector min(row_vector)-1];
j = 1;
for i=1:length(A)-2
temp=A(i:i+2);
if(max(temp)==temp(2))
peaks(j) = row_vector(i);
peak_indices(j) = i;
j = j+1;
end
end
end
Save it as find_peaks.m
Now, you can use it as:
>> A = [2 1 3 5 4 7 6 8 9];
>> [peaks, peak_indices] = find_peaks(A)
peaks =
2 5 7 9
peak_indices =
1 4 6 9
This would however give you "plateaus" as well (adjacent and equal "peaks").
You can use diff to do the comparison and add two points in the beginning and end to cover the border cases:
B=[1 diff(A) -1];
peak_indices = find(B(1:end-1)>=0 & B(2:end)<=0);
peaks = A(peak_indices);
It returns
peak_indices =
1 4 6 9
peaks =
2 5 7 9
for your example.
findpeaks does it if you have a recent matlab version, but it's also a bit slow.
This proposed solution would be quite slow due to the for loop, and you also have a risk of rounding error due to the fact that you compare the maximal value to the central one instead of comparing the position of the maximum, which is better for your purpose.
You can stack the data so as to have three columns : the first one for the preceeding value, the second is the data and the third one is the next value, do a max, and your local maxima are the points for which the position of the max along columns is 2.
I've coded this as a subroutine of my own peak detection function, that adds a further level of iterative peak detection
http://www.mathworks.com/matlabcentral/fileexchange/42927-find-peaks-using-scale-space-approach