Matlab, Find cell elements - string

I have two cell arrays of string A and B. All cells of B are also in A. I want to find the index of cell of B in A. Thanks.
Example:
A=
'aaaa'
'bbbb'
'cccc'
'dddd'
'ffff'
B=
'ffff'
'aaaa'
ans=
5
1
or
ans=
1
5

use either intersect or ismember
[~, idxInA] = intersect(A,B)
or
LocInA = find(ismember(A,B))

You can do this really simply, use the code below
indices = cell(size(B));
for i = 1:numel(B)
indices{i} = find(strcmpi(A,B(i)));
end
While I do recommend using ismember or intersect, those solutions will not handle case insensitive solutions. Also, those methods will not indicate how many times a specific index was matched, where my solution, will return all indices that match for each comparison.
UPDATE
Code I am running to test this.
A={'aaaa','bbbb','cccc','dddd','ffff','aaaa'};
B={'ffff','aaaa','cccc','qwerty'};
indices = cell(size(B));
for i = 1:numel(B)
indices{i} = find(strcmpi(A,B(i)));
end
indices
Which returns the following
indices =
[5] [1x2 double] [3] [1x0 double]
I do not see where you are having problems

Related

How can i optimise my code and make it readable?

The task is:
User enters a number, you take 1 number from the left, one from the right and sum it. Then you take the rest of this number and sum every digit in it. then you get two answers. You have to sort them from biggest to lowest and make them into a one solid number. I solved it, but i don't like how it looks like. i mean the task is pretty simple but my code looks like trash. Maybe i should use some more built-in functions and libraries. If so, could you please advise me some? Thank you
a = int(input())
b = [int(i) for i in str(a)]
closesum = 0
d = []
e = ""
farsum = b[0] + b[-1]
print(farsum)
b.pop(0)
b.pop(-1)
print(b)
for i in b:
closesum += i
print(closesum)
d.append(int(closesum))
d.append(int(farsum))
print(d)
for i in sorted(d, reverse = True):
e += str(i)
print(int(e))
input()
You can use reduce
from functools import reduce
a = [0,1,2,3,4,5,6,7,8,9]
print(reduce(lambda x, y: x + y, a))
# 45
and you can just pass in a shortened list instead of poping elements: b[1:-1]
The first two lines:
str_input = input() # input will always read strings
num_list = [int(i) for i in str_input]
the for loop at the end is useless and there is no need to sort only 2 elements. You can just use a simple if..else condition to print what you want.
You don't need a loop to sum a slice of a list. You can also use join to concatenate a list of strings without looping. This implementation converts to string before sorting (the result would be the same). You could convert to string after sorting using map(str,...)
farsum = b[0] + b[-1]
closesum = sum(b[1:-2])
"".join(sorted((str(farsum),str(closesum)),reverse=True))

How to multiply 2 values in list of (3) numbers and letters

I have a list(or it can be a dictionary):
A = [
['soda',9,3],
['cake',56,6],
['beer',17,10],
['candies',95,8],
['sugar',21,20]
]
And i need to find a multiply of last 2 values in each sublist and sum up this:
9*3+56*6+17*10+95*8+21*20
How can i do this?
It's a very basic question and has a really simple answer. Until you are sure that the format is the same, the following code will help you:
result = 0
for sub_list in A:
result += sub_list[-1] * sub_list[-2]
The result variable will store the result you want. sub_result is one of the sublists in A in each iteration.
sub_list[-1] is the last element of sub-list and `sub_list[-2] is the element before that.

comparing two arrays and get the values which are not common

I am doing this problem a friend gave me where you are given 2 arrays say (a[1,2,3,4] and b[8,7,9,2,1]) and you have to find not common elements.
Expected output is [3,4,8,7,9]. Code below.
def disjoint(e,f):
c = e[:]
d = f[:]
for i in range(len(e)):
for j in range(len(f)):
if e[i] == f[j]:
c.remove(e[i])
d.remove(d[j])
final = c + d
print(final)
print(disjoint(a,b))
I tried with nested loops and creating copies of given arrays to modify them then add them but...
def disjoint(e,f):
c = e[:] # list copies
d = f[:]
for i in range(len(e)):
for j in range(len(f)):
if e[i] == f[j]:
c.remove(c[i]) # edited this line
d.remove(d[j])
final = c + d
print(final)
print(disjoint(a,b))
when I try removing common element from list copies, I get different output [2,4,8,7,9]. why ??
This is my first question in this website. I'll be thankful if anyone can clear my doubts.
Using sets you can do:
a = [1,2,3,4]
b = [8,7,9,2,1]
diff = (set(a) | set(b)) - (set(a) & set(b))
(set(a) | set(b)) is the union, set(a) & set(b) is the intersection and finally you do the difference between the two sets using -.
Your bug comes when you remove the elements in the lines c.remove(c[i]) and d.remove(d[j]). Indeed, the common elements are e[i]and f[j] while c and d are the lists you are updating.
To fix your bug you only need to change these lines to c.remove(e[i]) and d.remove(f[j]).
Note also that your method to delete items in both lists will not work if a list may contain duplicates.
Consider for instance the case a = [1,1,2,3,4] and b = [8,7,9,2,1].
You can simplify your code to make it works:
def disjoint(e,f):
c = e.copy() # [:] works also, but I think this is clearer
d = f.copy()
for i in e: # no need for index. just walk each items in the array
for j in f:
if i == j: # if there is a match, remove the match.
c.remove(i)
d.remove(j)
return c + d
print(disjoint([1,2,3,4],[8,7,9,2,1]))
Try it online!
There are a lot of more effecient way to achieve this. Check this stack overflow question to discover them: Get difference between two lists. My favorite way is to use set (like in #newbie's answer). What is a set? Lets check the documentation:
A set object is an unordered collection of distinct hashable objects. Common uses include membership testing, removing duplicates from a sequence, and computing mathematical operations such as intersection, union, difference, and symmetric difference. (For other containers see the built-in dict, list, and tuple classes, and the collections module.)
emphasis mine
Symmetric difference is perfect for our need!
Returns a new set with elements in either the set or the specified iterable but not both.
Ok here how to use it in your case:
def disjoint(e,f):
return list(set(e).symmetric_difference(set(f)))
print(disjoint([1,2,3,4],[8,7,9,2,1]))
Try it online!

How to find two or more equal strings stored in two different vectors in matlab

I have two vectors (of different size) with strings in a data file.
I want to find the locations of two (or more) similar strings in each of these vectors.
E.g.:
a=['str1', 'str2', 'str3', 'str4', 'str5', 'str6'];
b=['str3', 'str1', 'str4', 'str4'];
I want an output like:
b(1) corresponds to a(3)
b(2) corresponds to a(1)
b(3) corresponds to a(4)
b(4) corresponds to a(4)
is it possible?
If you store your strings in cell arrays, you can do it like this:
>> a = {'str1', 'str2', 'str3', 'str4', 'str5', 'str6'};
>> b = {'str3', 'str1', 'str4', 'str4'};
>> result = cellfun(#(x) find(strcmp(a, x)), b, 'UniformOutput', false);
result =
[3] [1] [4] [4]
Note: result is a cell array. Therefore, result{i} == j means b(i) corresponds to a(j). If b(i) was not found in a, result{i} is empty.
An alternative is to use the ismember command which will return an array of logicals indicating whether the element of array b is a member of array a. It can also return a vector which indicates where in a the element of b is found. Using your example:
[ismem,idxa]=ismember(b,a)
returns the results
ismem =
1 1 1 1
idxa =
3 1 4 4
So we see that each member of b is in a (due to the ismem vector being all ones) and we see where in a is that element of b from the idxa vector. (Note that if b has an element that is not in a then there would be a zero element in both vectors.)

How to concat string + i?

for i=1:N
f(i) = 'f'+i;
end
gives an error in MatLab. What's the correct syntax to initialize an array with N strings of the pattern fi?
It seems like even this is not working:
for i=1:4
f(i) = 'f';
end
You can concatenate strings using strcat. If you plan on concatenating numbers as strings, you must first use num2str to convert the numbers to strings.
Also, strings can't be stored in a vector or matrix, so f must be defined as a cell array, and must be indexed using { and } (instead of normal round brackets).
f = cell(N, 1);
for i=1:N
f{i} = strcat('f', num2str(i));
end
For versions prior to R2014a...
One easy non-loop approach would be to use genvarname to create a cell array of strings:
>> N = 5;
>> f = genvarname(repmat({'f'}, 1, N), 'f')
f =
'f1' 'f2' 'f3' 'f4' 'f5'
For newer versions...
The function genvarname has been deprecated, so matlab.lang.makeUniqueStrings can be used instead in the following way to get the same output:
>> N = 5;
>> f = strrep(matlab.lang.makeUniqueStrings(repmat({'f'}, 1, N), 'f'), '_', '')
f =
1×5 cell array
'f1' 'f2' 'f3' 'f4' 'f5'
Let me add another solution:
>> N = 5;
>> f = cellstr(num2str((1:N)', 'f%d'))
f =
'f1'
'f2'
'f3'
'f4'
'f5'
If N is more than two digits long (>= 10), you will start getting extra spaces. Add a call to strtrim(f) to get rid of them.
As a bonus, there is an undocumented built-in function sprintfc which nicely returns a cell arrays of strings:
>> N = 10;
>> f = sprintfc('f%d', 1:N)
f =
'f1' 'f2' 'f3' 'f4' 'f5' 'f6' 'f7' 'f8' 'f9' 'f10'
Using sprintf was already proposed by ldueck in a comment, but I think this is worth being an answer:
f(i) = sprintf('f%d', i);
This is in my opinion the most readable solution and also gives some nice flexibility (i.e. when you want to round a float value, use something like %.2f).
according to this it looks like you have to set "N" before trying to use it and it looks like it needs to be an int not string? Don't know much bout MatLab but just what i gathered from that site..hope it helps :)
Try the following:
for i = 1:4
result = strcat('f',int2str(i));
end
If you use this for naming several files that your code generates, you are able to concatenate more parts to the name. For example, with the extension at the end and address at the beginning:
filename = strcat('c:\...\name',int2str(i),'.png');

Resources