Filter out combinations in Matlab - arrays

Currently I can generate all the combinations from categories alpha, beta, gamma and delta (1 1 1 1, 1 1 1 2 etc.).
Current code:
alpha = [1, 2, 3];
beta = [1, 2, 3, 4, 5];
gamma = [1, 2, 3, 4, 5];
delta = [1, 2, 3];
[a, b, c, d] = ndgrid (alpha, beta, gamma, delta);
combination = [a(:), b(:), c(:), d(:)];
I want to filter out some of those combinations i.e. get rid of any of the combinations where alpha is 1 and gamma is 4 etc.
How would I approach this?

What you're looking for is logical indexing
c1 = (combination(:,1) ~= 1); %rows where alpha is not 1
c2 = (combination(:,3) ~= 4); %rows where gamma is not 4
desired = combination(c1&c2,:); %output rows where both c1 and c2 are true

Ian Riley's answer has provided the correct approach if you want to create a new array from that information. Just adding to his answer that you can also use the same approach to remove the unwanted rows directly, by setting them to empty, i.e.:
>> combination(combination(:,1) == 1,:) = [];
>> combination(combination(:,3) == 4,:) = [];

Related

Matlab diff command with bigger step

The command diff calculates differences between two consecutive elements. Is there any way to calculates differences between two nonconsecutive elements?
For example, with
x = [1,2,3,4,5,6]
is there any command to find
[x(3)-x(1),x(4)-x(2),x(5)-x(3),x(6)-x(4)] = [2,2,2,2]
or
[x(4)-x(1),x(5)-x(2),x(6)-x(3)] = [3,3,3]
And in general, for the case of a matrix? I can write some code for this; I just wonder if there any existing command in Matlab for this?
An example of the matrix case
x = [1,2,3,4;1,3,5,7;2,4,6,8]
and we want to find
[x(1,3)-x(1,1),x(1,4)-x(1,2);x(2,3)-x(2,1),x(2,4)-x(2,2);x(3,3)-x(3,1),x(3,4)-x(3,2)] = [2,2;4,4;4,4]
For vectors
I would use convolution with kernel [1 0 ยทยทยท 0 -1], where the number of zeros depends on the desired step. This can be done with function conv:
x = [1,2,3,4,5,6]; % data
s = 2; % step
result = conv(x, [1 zeros(1,s-1) -1], 'valid');
gives
result =
2 2 2 2
For matrices or N-dimensional arrays
The above can be generalized using convn, with a kernel defined as before but oriented along the desired dimension:
x = [1,2,3,4; 1,3,5,7; 2,4,6,8]; % data
s = 2; % step
d = 2; % dimension
result = convn(x, reshape(([1 zeros(1,s-1) -1]), [ones(1,d-1) s+1 1]), 'valid');
gives
result =
2 2
4 4
4 4
I'm not aware of such a function, but you can simply set up a very simple anonymous function
stepDiff = #(x, s) x(:, s:end)-x(:, 1:end-s+1);
Will give outputs like:
x = [1, 2, 3, 4, 5, 6];
>> stepDiff(x, 2)
ans =
1 1 1 1 1
>> stepDiff(x, 4)
ans =
3 3 3
x = [1, 2, 3, 4; 1, 3, 5, 7; 2, 4, 6, 8];
>> stepDiff(x, 3)
ans =
2 2
4 4
4 4

Finding (multiset) difference between two arrays

Given arrays (say row vectors) A and B, how do I find an array C such that merging B and C will give A?
For example, given
A = [2, 4, 6, 4, 3, 3, 1, 5, 5, 5];
B = [2, 3, 5, 5];
then
C = multiset_diff(A, B) % Should be [4, 6, 4, 3, 1, 5]
(the order of the result does not matter here).
For the same A, if B = [2, 4, 5], then the result should be [6, 4, 3, 3, 1, 5, 5].
(Since there were two 4s in A and one 4 in B, the result C should have 2 - 1 = 1 4 in it. Similarly for the other values.)
PS: Note that setdiff would remove all instances of 2, 3, and 5, whereas here they need to be removed just however many times they appear in B.
Performance: I ran some quick-n-dirty benchmarks locally, here are the results for future reference:
#heigele's nested loop method performs best for small lengths of A (say upto N = 50 or so elements). It does 3x better for small (N=20) As, and 1.5x better for medium-sized (N=50) As, compared to the next best method - which is:
#obchardon's histc-based method. This is the one performs the best when A's size N starts to be 100 and above. For eg., this does 3x better than the above nested loop method when N = 200.
#matt's for+find method does comparably to the histc method for small N, but quickly degrades in performance for larger N (which makes sense since the entire C == B(x) comparison is run every iteration).
(The other methods are either several times slower or invalid at the time of writing.)
Still another approach using the histc function:
A = [2, 4, 6, 4, 3, 3, 1, 5, 5, 5];
B = [2, 3, 5, 5];
uA = unique(A);
hca = histc(A,uA);
hcb = histc(B,uA);
res = repelem(uA,hca-hcb)
We simply calculate the number of repeated elements for each vectors according to the unique value of vector A, then we use repelem to create the result.
This solution do not preserve the initial order but it don't seems to be a problem for you.
I use histc for Octave compatibility, but this function is deprecated so you can also use histcounts
Here's a vectorized way. Memory-inefficient, mostly for fun:
tA = sum(triu(bsxfun(#eq, A, A.')), 1);
tB = sum(triu(bsxfun(#eq, B, B.')), 1);
result = setdiff([A; tA].', [B; tB].', 'rows', 'stable');
result = result(:,1).';
The idea is to make each entry unique by tagging it with an occurrence number. The vectors become 2-column matrices, setdiff is applied with the 'rows' option, and then the tags are removed from the result.
You can use the second output of ismember to find the indexes where elements of B are in A, and diff to remove duplicates:
This answer assumes that B is already sorted. If that is not the case, B has to be sorted before executing above solution.
For the first example:
A = [2, 4, 6, 4, 3, 3, 1, 5, 5, 5];
B = [2, 3, 5, 5];
%B = sort(B); Sort if B is not sorted.
[~,col] = ismember(B,A);
indx = find(diff(col)==0);
col(indx+1) = col(indx)+1;
A(col) = [];
C = A;
>>C
4 6 4 3 1 5
For the second example:
A = [2, 4, 6, 4, 3, 3, 1, 5, 5, 5];
B = [2, 4, 5, 5];
%B = sort(B); Sort if B is not sorted.
[~,col] = ismember(B,A);
indx = find(diff(col)==0);
col(indx+1) = col(indx)+1;
A(col) = [];
C = A;
>>C
6 4 3 3 1 5
I'm not a fan of loops, but for random perturbations of A this was the best I came up with.
C = A;
for x = 1:numel(B)
C(find(C == B(x), 1, 'first')) = [];
end
I was curious about looking at the affect of different orders of A on a solution approach so I setup a test like this:
Ctruth = [1 3 3 4 5 5 6];
for testNumber = 1:100
Atest = A(randperm(numel(A)));
C = myFunction(Atest,B);
C = sort(C);
assert(all(C==Ctruth));
end
Strongly inspired by Matt, but on my machine 40% faster:
function A = multiDiff(A,B)
for j = 1:numel(B)
for i = 1:numel(A)
if A(i) == B(j)
A(i) = [];
break;
end
end
end
end

How to swap two row vectors inside a row vector?

i am trying to swap 2 row vectors which are inside a row vector.
For example:
a=[1 2 3];
b=[5 3];
c=[9 3 7 6];
d=[7 5];
X1= [ a, b , d, c ];
I want to do random swapping such that two of the a,b,c,d remains at the same position in X1 and the remaining two of them shuffles in X1. For example, some of the possible random swaps are:
[b,a,d,c] % a and b swap with each other whereas d and c remain at the same place
[d,b,a,c] % a and d swap with each other whereas b and c remain at the same place
[c,b,d,a] % a and c swap with each other whereas b and d remain at the same place
.....
.....
The proper and safe way to what you're trying to do is by assigning your variables to a cell, permuting the elements of the cell, and finally concatenating the result.
Imagine a specific permutation, say, [c, b, a, d]. This permutation can be coded as [3, 2, 1, 4] in terms of a mapping. The corresponding code to generate your array is then:
% generate input
a = [1, 2, 3];
b = [5, 3];
c = [9, 3, 7, 6];
d = [7, 5];
% generate cell to permute
tmpcell = {a, b, c, d};
% define our permutation
permnow = [3, 2, 1, 4];
% permute and concatenate the result into an array
result = [tmpcell{permnow}];
% check if this is indeed OK:
disp(isequal(result,[c, b, a, d])) % should print 1
The only thing you might still need is to generate a random configuration. This is easy: you just have to choose 2 random indices and swap them in [1, 2, 3, 4]. A lazy option to do this:
nvars = length(tmpcell); % generalizes to multiple variables this way
idperm = 1:nvars;
i1 = randi(nvars,1);
partperm = setdiff(idperm, i1); % vector of remaining indices, avoid duplication
i2 = partperm(randi(nvars-1,1)); % second index, guaranteed distinct from i1
permnow = idperm;
permnow([i1, i2]) = [i2, i1]; % swap the two indices

Define multiple variables at the same time in MATLAB

I want to define multiple variables at the same time.
For example, I want to define
a = 1
b = 2
c = 3
like this.
So I made a matrix with [a,b,c]:
x = [a, b, c];
y = [1, 2, 3];
x = y
So I want to get the following answer.
a = 1
b = 2
c = 3
If I use
[a, b, c] = deal(1, 2, 3)
then, I can get
a = 1
b = 2
c = 3
But I want to use matrix x instead of [a, b, c]
So if I use,
x = deal(1,2,3)
there is an error.
Is there any solution?
Maybe I don't understand the question but if you want to use the matrix x instead of [a, b, c] why don't you just define it as
x = [1, 2, 3];
From your question it sounds to me as if you are overcomplicating the problem. You begin by wanting to declare
a = 1;
b = 2;
c = 3;
but what you want instead according to the end of your question is
x = [1, 2, 3];
If you define x as above you can the refer to the individual elements of x like
>> x(1), x(2), x(3)
ans =
1
ans =
2
ans =
3
Now you have the best of both worlds with 1 definition. You can refer to a, b and c using x(1), x(2), x(3) instead and you've only had to define x once with x = [1, 2, 3];.
You cannot deal into a numeric array, but you can deal into a cell array and then concatenate all the elements in the cell array, like this:
[x{1:3}] = deal(1, 2, 3); % x is a cell array {1, 2, 3}
x = [x{:}]; % x is now a numeric array [1, 2, 3]

python checking if one list can equal another (in value and order) if elements in one are deleted

I have two lists of input (call one a, the other b), I am trying to see if a can be matched to b if elements of a are removed. For example if a = [1, 1, 2, 3, 3, 3, 4] and b = [1,2,3] , the function would find that it can remove one occurrence of 1, two occurrences of 3 and the only occurrence of 4 so that a == b. I don't know how I would go about getting this to work in Python.
a = [1, 1, 2, 3, 3, 3, 4]
b = [1, 2, 3]
i = 0
ans = False
if len(a) >= len(b):
for item in a:
if item == b[i]:
i += 1
if i >= len(b):
ans = True
break
print ans
Not quite as efficient as sophiadw's answer, but this approach will tell you which items in a aren't needed to match b, and the input lists don't need to be sorted.
from collections import Counter
#returns False if a can't be pared down to match b.
#If it can be pared down, returns a dictionary of which items to remove.
def can_match(a,b):
c_a = Counter(a)
c_b = Counter(b)
if c_b - c_a:
return False
return c_a - c_b
a = [1,1,2,3,3,3,4]
b = [1,2,3]
print can_match(a,b)
Result:
Counter({3: 2, 1: 1, 4: 1})

Resources