Counting arrays in loop - arrays

I have a loop...
while($rows=mysql_fetch_array($result))
{
$staff[] = $rows['staff'];
$a = array_count_values($staff);
$b = count($a);
echo"$b<br>";
}
that output
1
1
1
2
2
2
3
3
4
5
5
on my research, it must be and I wanted the result to be this way
3 (is equal to three 1's)
3 (is equal to three 2's)
2 (is equal to two 3)
1 (is equal to one 4)
2 (is equal to two 5's)
any help?
what I want is to get the number of same element in an array

As far as I understand your concern, this should do the trick:
$staff = array();
while($rows=mysql_fetch_array($result))
{
$staff[] = $rows['staff'];
}
$a = array_count_values($staff);
print_r($a);

Related

Shuffle array while spacing repeating elements

I'm trying to write a function that shuffles an array, which contains repeating elements, but ensures that repeating elements are not too close to one another.
This code works but seems inefficient to me:
function shuffledArr = distShuffle(myArr, myDist)
% this function takes an array myArr and shuffles it, while ensuring that repeating
% elements are at least myDist elements away from on another
% flag to indicate whether there are repetitions within myDist
reps = 1;
while reps
% set to 0 to break while-loop, will be set to 1 if it doesn't meet condition
reps = 0;
% randomly shuffle array
shuffledArr = Shuffle(myArr);
% loop through each unique value, find its position, and calculate the distance to the next occurence
for x = 1:length(unique(myArr))
% check if there are any repetitions that are separated by myDist or less
if any(diff(find(shuffledArr == x)) <= myDist)
reps = 1;
break;
end
end
end
This seems suboptimal to me for three reasons:
1) It may not be necessary to repeatedly shuffle until a solution has been found.
2) This while loop will go on forever if there is no possible solution (i.e. setting myDist to be too high to find a configuration that fits). Any ideas on how to catch this in advance?
3) There must be an easier way to determine the distance between repeating elements in an array than what I did by looping through each unique value.
I would be grateful for answers to points 2 and 3, even if point 1 is correct and it is possible to do this in a single shuffle.
I think it is sufficient to check the following condition to prevent infinite loops:
[~,num, C] = mode(myArr);
N = numel(C);
assert( (myDist<=N) || (myDist-N+1) * (num-1) +N*num <= numel(myArr),...
'Shuffling impossible!');
Assume that myDist is 2 and we have the following data:
[4 6 5 1 6 7 4 6]
We can find the the mode , 6, with its occurence, 3. We arrange 6s separating them by 2 = myDist blanks:
6 _ _ 6 _ _6
There must be (3-1) * myDist = 4 numbers to fill the blanks. Now we have five more numbers so the array can be shuffled.
The problem becomes more complicated if we have multiple modes. For example for this array [4 6 5 1 6 7 4 6 4] we have N=2 modes: 6 and 4. They can be arranged as:
6 4 _ 6 4 _ 6 4
We have 2 blanks and three more numbers [ 5 1 7] that can be used to fill the blanks. If for example we had only one number [ 5] it was impossible to fill the blanks and we couldn't shuffle the array.
For the third point you can use sparse matrix to accelerate the computation (My initial testing in Octave shows that it is more efficient):
function shuffledArr = distShuffleSparse(myArr, myDist)
[U,~,idx] = unique(myArr);
reps = true;
while reps
S = Shuffle(idx);
shuffledBin = sparse ( 1:numel(idx), S, true, numel(idx) + myDist, numel(U) );
reps = any (diff(find(shuffledBin)) <= myDist);
end
shuffledArr = U(S);
end
Alternatively you can use sub2ind and sort instead of sparse matrix:
function shuffledArr = distShuffleSparse(myArr, myDist)
[U,~,idx] = unique(myArr);
reps = true;
while reps
S = Shuffle(idx);
f = sub2ind ( [numel(idx) + myDist, numel(U)] , 1:numel(idx), S );
reps = any (diff(sort(f)) <= myDist);
end
shuffledArr = U(S);
end
If you just want to find one possible solution you could use something like that:
x = [1 1 1 2 2 2 3 3 3 3 3 4 5 5 6 7 8 9];
n = numel(x);
dist = 3; %minimal distance
uni = unique(x); %get the unique value
his = histc(x,uni); %count the occurence of each element
s = [sortrows([uni;his].',2,'descend'), zeros(length(uni),1)];
xr = []; %the vector that will contains the solution
%the for loop that will maximize the distance of each element
for ii = 1:n
s(s(:,3)<0,3) = s(s(:,3)<0,3)+1;
s(1,3) = s(1,3)-dist;
s(1,2) = s(1,2)-1;
xr = [xr s(1,1)];
s = sortrows(s,[3,2],{'descend','descend'})
end
if any(s(:,2)~=0)
fprintf('failed, dist is too big')
end
Result:
xr = [3 1 2 5 3 1 2 4 3 6 7 8 3 9 5 1 2 3]
Explaination:
I create a vector s and at the beggining s is equal to:
s =
3 5 0
1 3 0
2 3 0
5 2 0
4 1 0
6 1 0
7 1 0
8 1 0
9 1 0
%col1 = unique element; col2 = occurence of each element, col3 = penalities
At each iteration of our for-loop we choose the element with the maximum occurence since this element will be harder to place in our array.
Then after the first iteration s is equal to:
s =
1 3 0 %1 is the next element that will be placed in our array.
2 3 0
5 2 0
4 1 0
6 1 0
7 1 0
8 1 0
9 1 0
3 4 -3 %3 has now 5-1 = 4 occurence and a penalities of -3 so it won't show up the next 3 iterations.
at the end every number of the second column should be equal to 0, if it's not the minimal distance was too big.

How can I get no. of Swap operations to form the 2nd Array

I have got two arrays with same elements... (But in different order)
e.g 1 2 12 9 7 15 22 30
and 1 2 7 12 9 20 15 22
how many swaps operations are needed to form the 2nd array from the first.?
I have tried taking no. of different elements for each index and dividing the result by 2 but that isn't fetching me the right answer...
One classic algorithm seems to be permutation cycles (https://en.m.wikipedia.org/wiki/Cycle_notation#Cycle_notation). The number of swaps needed equals the total number of elements subtracted by the number of cycles.
For example:
1 2 3 4 5
2 5 4 3 1
Start with 1 and follow the cycle:
1 down to 2, 2 down to 5, 5 down to 1.
1 -> 2 -> 5 -> 1
3 -> 4 -> 3
We would need to swap index 1 with 5, then index 5 with 2; as well as index 3 with index 4. Altogether 3 swaps or n - 2. We subtract n by the number of cycles since cycle elements together total n and each cycle represents a swap less than the number of elements in it.
1) re-index elements from 0 to n-1. In your example, arrayA becomes 0..7 and arrayB becomes 0 1 4 2 3 7 5 6.
2) sort the second array using your swapping algorithm and count the number of operations.
A bit naive, but I think you can use recursion as follows (pseudo code):
function count_swaps(arr1, arr2):
unless both arrays contain the same objects return false
if arr1.len <= 1 return 0
else
if arr1[0] == arr2[0] return count_swaps(arr1.tail, arr2.tail)
else
arr2_tail = arr2.tail
i = index_of arr1[0] in arr2_tail
arr2_tail[i] = arr2[0]
return 1+count_swaps(arr1.tail, arr2_tail)
Here's a ruby implementation:
require 'set'
def count_swaps(a1, a2)
raise "Arrays do not have the same objects: #{a1} #{a2}" unless a1.length == a2.length && Set[*a1]==Set[*a2]
return count_swap_rec(a1, a2)
end
def count_swap_rec(a1, a2)
return 0 if a1.length <= 1
return count_swaps(a1[1..-1], a2[1..-1]) if a1[0] == a2[0]
a2_tail = a2[1..-1]
a2_tail[a2_tail.find_index(a1[0])] = a2[0]
return 1 + count_swaps(a1[1..-1], a2_tail)
end

Removing any two array values whose difference is a member of that array

I am trying to remove array values whose difference is a member of that array in MATLAB. For example, if I have an array defined as
x = [1 2 4 3 7];
I would like to remove 2, because it can be achieved from 4 - 2. I would also like to remove 4 because it can be achieved from 7 - 3. I would then like to store these values (2 and 4, respectively) into a matrix. The latter is easy. I just have a hard time doing this checker for summation.
I know you can use
ismember(*any 2 differences*),x(:))
to check if the differences are in the array. However, I don't know how to code my function to try out all the combinations of element subtraction.
Seemed like a good setup to use bsxfun -
abs_diffs = abs(bsxfun(#minus,x(:),x(:).')) %//'
unq_abs_diffs = unique(abs_diffs)
out = x(~any(bsxfun(#eq,unq_abs_diffs(:),x(:).'),1)) %//'
%// OR x(~ismember(x,unq_abs_diffs))
Sample run -
>> x
x =
1 2 4 3 7
>> abs_diffs = abs(bsxfun(#minus,x(:),x(:).'))
abs_diffs =
0 1 3 2 6
1 0 2 1 5
3 2 0 1 3
2 1 1 0 4
6 5 3 4 0
>> unq_abs_diffs = unique(abs_diffs)
unq_abs_diffs =
0
1
2
3
4
5
6
>> out = x(~any(bsxfun(#eq,unq_abs_diffs(:),x(:).'),1))
out =
7
So, in [1 2 4 3 7], only 7 seemed like the one that could not be removed.
You could do it like this:
n = length(a);
differences = meshgrid(a,a) - meshgrid(a,a)'; % get differences between elements
differences(1:n+1:n*n) = []; % remove diagonal
a(ismember(a,differences)) = []; % remove elements in differences
I'm assuming that you only want differences between unique elements. If you want to allow the difference between an element of a and itself, then remove the 3rd line.

Find 10 most repeated elements in a vector in MATLAB

I'm suppose to find 10 most repeated elements in a vector with n elements,
(the elements are from 1-100)
does anyone know how to do that?
I know how to find the one that is most repeated element in a vector but I don't know how to find 10 most repeated elements with n being unknown.
a = randi(10,1,100);
y = hist(a,1:max(a));
[~,ind] = sort(y,'descend');
out = ind(1:10);
for number of occurrences use y(ind(1:10)).
I had some doubts so I tested it many times, it seems to work.
You can use unique for that case. In my example, I have 4 numbers and I want to grep the 2 with the most occurances.
A = [1 1 3 3 1 1 2 2 1 1 1 2 3 3 3 4 4 4 4];
B = sort(A); % Required for the usage of unique below
[~,i1] = unique(B,'first');
[val,i2] = unique(B,'last');
[~,pos] = sort(i2-i1,'descend');
val(pos(1:2))
1 3
Replace val(pos(1:2)) by val(pos(1:10)) in your case to get the 10 most values. The get the number of elements you can use i1 and i2.
num = i2-i1+1;
num(1:2)
ans =
7 3
Since you already know how to find the most repeated element, you could use the following algorithm:
Find the most repeated element of the vector
Remove the most repeated element from the vector
Repeat the process on the new vector to find the 2nd most repeated element
Continue until you have the 10 most repeated elements
The code would look something like:
count = 0;
values = [];
while count < 10
r = Mode(Vector);
values = [values r]; % store most repeated values
Vector = Vector(find(Vector~=r));
count = count + 1;
end
Not efficient, but it'll get the job done

matlab: eliminate elements from array

I have quite big array. To make things simple lets simplify it to:
A = [1 1 1 1 2 2 3 3 3 3 4 4 5 5 5 5 5 5 5 5];
So, there is a group of 1's (4 elements), 2's (2 elements), 3's (4 elements), 4's (2 elements) and 5's (8 elements). Now, I want to keep only columns, which belong to group of 3 or more elements. So it will be like:
B = [1 1 1 1 3 3 3 3 5 5 5 5 5 5 5 5];
I was doing it using for loop, scanning separately 1's, 2's, 3's and so on, but its extremely slow with big arrays...
Thanks for any suggestions how to do it in more efficient way :)
Art.
A general approach
If your vector is not necessarily sorted, then you need to run to count the number of occurrences of each element in the vector. You have histc just for that:
elem = unique(A);
counts = histc(A, elem);
B = A;
B(ismember(A, elem(counts < 3))) = []
The last line picks the elements that have less than 3 occurrences and deletes them.
An approach for a grouped vector
If your vector is "semi-sorted", that is if similar elements in the vector are grouped together (as in your example), you can speed things up a little by doing the following:
start_idx = find(diff([0, A]))
counts = diff([start_idx, numel(A) + 1]);
B = A;
B(ismember(A, A(start_idx(counts < 3)))) = []
Again, note that the vector need not to be entirely sorted, just that similar elements are adjacent to each other.
Here is my two-liner
counts = accumarray(A', 1);
B = A(ismember(A, find(counts>=3)));
accumarray is used to count the individual members of A. find extracts the ones that meet your '3 or more elements' criterion. Finally, ismember tells you where they are in A. Note that A needs not be sorted. Of course, accumarray only works for integer values in A.
What you are describing is called run-length encoding.
There is software for this in Matlab on the FileExchange. Or you can do it directly as follows:
len = diff([ 0 find(A(1:end-1) ~= A(2:end)) length(A) ]);
val = A(logical([ A(1:end-1) ~= A(2:end) 1 ]));
Once you have your run-length encoding you can remove elements based on the length. i.e.
idx = (len>=3)
len = len(idx);
val = val(idx);
And then decode to get the array you want:
i = cumsum(len);
j = zeros(1, i(end));
j(i(1:end-1)+1) = 1;
j(1) = 1;
B = val(cumsum(j));
Here's another way to do it using matlab built-ins.
% Set up
A=[1 1 1 1 2 2 3 3 3 3 4 4 5 5 5 5 5];
threshold=2;
% Get the unique elements of the array
uniqueElements=unique(A);
% Count haw many times each unique element occurs
counts=histc(A,uniqueElements);
% Write which elements should be kept
toKeep=uniqueElements(counts>threshold);
% Make a logical index
indexer=false(size(A));
for i=1:length(toKeep)
% For every unique element we want to keep select the indices in A that
% are equal
indexer=indexer|(toKeep(i)==A);
end
% Apply index
B=A(indexer);

Resources