I am doing some classification and needed to convert an integer code to strings for that reason. I wrote something like this:
s(1).class = 1;
s(2).class = 7;
s(3).class = 9;
[s([find([s.class] == 1)]).class] = deal('c1'); %first conversion
[s([find([s.class] > 1)]).class] = deal('c2'); %second conversion
and was surprised to find s being a 1x4 struct array after the second conversion instead of the expected 1x3 struct array with the values.
Now, after some research, I understand that after the first conversion the value of s(1).class is 'c1' and the argument to find in the second conversion is not what I assumed it would be. The [s.class] statement actually returns something like the string 'c1\a\t' with ASCII escape sequences for bell and horizontal tab.
As the comparison does work (returning the matrix [1 1 1 1] and thus expanding my structure) I assume that matlab converts either the operand [s.class] or the operand 1.
Which is it? What actually is compared here numbers or characters?
And on the other hand is there a built in way to make > more restrictive, i. e. to require the operands to be of the same type and if not to throw an error?
When you do the comparison 'ab' > 1, the char array 'ab' gets converted to a double array, namely the ASCII codes of the characters. So 'ab' > 1 is equivalent to double('ab') > 1, which gives [1 1].
To get the behaviour you want (issue an error if one of the arguments is char) you could define a function:
function z = greaterthan(x,y)
if ischar(x) || ischar(y)
error('Invalid comparison: one of the input arguments is of type char')
else
z = x>y;
end
so that
>> greaterthan([0 1 2], 1)
ans =
0 0 1
>> greaterthan('ab', 1)
??? Error using ==> greaterthan at 3
Invalid comparison between char and int
Because you have not provided any expected output yet, I am going with the observations.
You are using a comprehension method (by invoking find) to determine which locations you will be populating for struct s with the results from your method deal (takes the argument c1 and c2). You have already set your type for s{whatever).class in the first snippet you provided. Which means it is number you are comparing, not character.
There is this isa function to see which class your variable belongs to. Use that to see what it is you are actually putting in (should say int32 for your case).
Related
I am currently learning python, but also other programming languages. Now I've run into a dilemma. I have the following code that i need to translate to three different programming languages, but before I do that I want to know in detail how the code works. The code (in python) is :
my_secret_key = 5
def decrypt(secret_string, secret_number):
result = ""
for x in secret_string:
result = result + chr(ord(x) ^ int(secret_number))
return result
print(decrypt("alq%lv%``k%b`m`lh", my_secret_key))
Now I have basic knowledge of Python and understand parts of this code, but the calculation it is making is difficult for me to understand.
Are there people willing to help me translate this code to human language so I can then find my way to translate this into other programming languages.
Thanks!
I have tried to look up the functions of chr and ord, and combined this with the x ^ int(secret_number). I tried to devide the code into blocks which helped me understand parts of it.
I tried just applying the calculation blocks but that doesnt work, it needs the full code to work
Explained with comments above each line:
def decrypt(secret_string, secret_number):
result = ""
# for each character in the encrypted string:
for x in secret_string:
# 1. convert the character to `int` using the `ord` function
# 2. convert the secret_number to `int` using the `int` function (this
# is redundant is this example, as `my_secret_key` is already `int`)
# 3. XOR the two integers with each other
# 4. convert the result from `int` back to `char` (actually 1-element
# string) using `chr`, and append it to the result string
result = result + chr(ord(x) ^ int(secret_number))
# return the decrypted string
return result
Regarding the ^ operator, from Python docs:
The ^ operator yields the bitwise XOR (exclusive OR) of its arguments [...]
This means that the result is an integer, whose binary representation will have:
zeros on bit positions where both arguments had 0, or both arguments had 1
ones on bit positions where one of the arguments had 0, and the other had 1
Example:
argument 1: 001 (binary), 1 (decimal)
argument 2: 011 (binary), 3 (decimal)
---
XOR result: 010 (binary), 2 (decimal)
^
bits in argument 1 and 2 on this position have different values,
so the result is 1
You can find more info on the XOR operation e.g. on Wikipedia: Exclusive or, XOR Cipher
I know there are already at least two topics that explain how map() works but I can't seem to understand its workings in a specific case I encountered.
I was working on the following Python exercise:
Write a program that computes the net amount of a bank account based a
transaction log from console input. The transaction log format is
shown as following:
D 100
W 200
D means deposit while W means withdrawal. Suppose the following input
is supplied to the program:
D 300
D 300
W 200
D 100
Then, the output should be:
500
One of the answers offered for this exercise was the following:
total = 0
while True:
s = input().split()
if not s:
break
cm,num = map(str,s)
if cm=='D':
total+=int(num)
if cm=='W':
total-=int(num)
print(total)
Now, I understand that map applies a function (str) to an iterable (s), but what I'm failing to see is how the program identifies what is a number in the s string. I assume str converts each letter/number/etc in a string type, but then how does int(num) know what to pick as a whole number? In other words, how come this code doesn't produce some kind of TypeError or ValueError, because the way I see it, it would try and make an integer of (for example) "D 100"?
first
cm,num = map(str,s)
could be simplified as
cm,num = s
since s is already a list of strings made of 2 elements (if the input is correct). No need to convert strings that are already strings. s is just unpacked into 2 variables.
the way I see it, it would try and make an integer of (for example) "D 100"?
no it cannot, since num is the second parameter of the string.
if input is "D 100", then s is ['D','100'], then cm is 'D' and num is '100'
Then since num represents an integer int(num) is going to convert num to its integer value.
The above code is completely devoid of error checking (number of parameters, parameters "type") but with the correct parameters it works.
and map is completely useless in that particular example too.
The reason is the .split(), statement before in the s = input().split(). This creates a list of the values D and 100 (or ['D', '100']), because the default split character is a space ( ). Then the map function applies the str operation to both 'D' and '100'.
Now the map, function is not really required because both values upon input are automatically of the type str (strings).
The second question is how int(num) knows how to convert a string. This has to do with the second (implicit) argument base. Similar to how .split() has a default argument of the character to split on, so does num have a default argument to convert to.
The full code is similar to int(num, base=10). So as long as num has the values 0-9 and at most 1 ., int can convert it properly to the base 10. For more examples check out built in int.
I have a mixed cell array with strings and integers. For example:
myData = {'blank' 'a' 'b' 'c'; ...
'sample1' 5 6 'NF'; ...
'sample2' 'NF' 54 'NF'};
I want to go in this cell array, find all instances of 'NF' and turn it into a 0.
Simple solution using strcmp
myData(strcmp(myData,'NF'))={0}
You could do this with cellfun and isequal:
myData(cellfun(#(c) isequal(c, 'NF'), myData)) = {0};
Or you could use strcmp as Jon suggests:
myData(strcmp(myData, 'NF')) = {0};
However, It should be noted that these two solutions aren't exactly equivalent in every case. From the documentation for strcmp:
The strcmp function is intended for comparison of text. If used on unsupported data types, strcmp always returns 0.
So, if either input argument is a data type other than a character vector/array, cell array of character vectors, or string array, strcmp will return false. Conversely, isequal ignores the data type of the input arguments in determining whether they are equal. For example, the numeric vector [78 70] is the ASCII equivalent of the character vector 'NF', so you get the following results from strcmp and isequal:
>> strcmp([78 70], 'NF')
ans =
logical
0 % No match
>> isequal([78 70], 'NF')
ans =
logical
1 % Match
In other words, strcmp is much stricter when comparing the equality of different data types, whereas isequal is more lax, allowing for inputs of different data types to be considered equal when their underlying data is effectively the same. You should consider which behavior is desired before choosing a solution.
A double for loop can solve this:
for j=1:size(myData,1)
for k=1:size(myData,2)
if strcmp(myData{j,k},'NF')
myData{j,k}=0;
end
end
end
where size(myData,1) finds the number of rows and size(myData,2) finds the number of columns of your mixed cell array.
I'm trying to make a function in Octave to check whether a string contains three consecutive same characters. That is, if my string is "asdf" it should return 0 and if it's like "asdfffg" it should return 1. What I did so far is this
if(length(findstr(word,"aaa",0)) > 1 || length(findstr(word,"bbb",0)) > 1 || ..
It's costly and I think not that really inefficient. Any suggestions?
Use a regular expression:
match = regexp(word, '(.)\1{2}', 'once');
This means: match any character ((.)), followed by that same character (\1) twice ({2}). It will return the starting index of the first match, or an empty array if there isn't any match. So your desired result would be
result = ~isempty(match);
Another possibility is to use convolution:
result = any(conv([1 1], +~diff(word))==2);
This works as follows: diff will give 0 when two consecutive characters are the same. So you want to detect if the output of diff contains two consecutive zeros. This is done by negating (~), converting to double (+), convolving with the sequence [1 1] (conv([1 1], ...)), and seeing if 2 is present in the output.
I would like to have a procedure which makes a local copy b of input character a (of not assumed length) into an allocatable array of characters. I do have the following code
program test_copystr
character(len=6) :: str
str = 'abc'
call copystr(str)
contains
subroutine copystr(a)
character(len=*), intent(in) :: a
!> Local variables
integer :: i
character, allocatable :: b(:)
allocate(b(len_trim(a)))
do i=1, len_trim(a)
b(i) = a(i:i)
end do
print *, b
b(1:len_trim(a)) = a(1:len_trim(a))
print *, b
end subroutine copystr
end program test_copystr
where I'm trying to assign a to b in two different ways. The result is
abc
aaa
I thought that both assignments should yield the same output. Can anyone explain me that difference? (To compile this code I'm using gfortran 5.2.0 compiler.)
As you know b is an array of characters while a is a scalar; when the subroutine is called it is a 6-character string. These are different things. The statement
b(1:len_trim(a)) = a(1:len_trim(a))
specifies the array section b(1:3) on the lhs, that is all 3 elements of b, and the substring a(1:3) on the rhs. Now, when assigning a substring of length 3 to a single character such as any element of b Fortran assigns only the first character of the string.
In this case every element of b is set to the first character of a. It is as if the compiler generates the 3 statements
b(1) = 'abc'
b(2) = 'abc'
b(3) = 'abc'
to implement the array assignment. This is what Fortran's array syntax does with an array on the lhs and a scalar (expression) on the rhs, it broadcasts the scalar to each element of the array.
The first method you use, looping across the elements of b and the characters of a is the regular way make an array of characters equivalent to a string. But you could try transfer -- see my answer to this question Removing whitespace in string