Inner workings of map() in a specific parsing situation - python-3.x

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.

Related

Python ord() and chr()

I have:
txt = input('What is your sentence? ')
list = [0]*128
for x in txt:
list[ord(x)] += 1
for x in list:
if x >= 1:
print(chr(list.index(x)) * x)
As per my understanding this should just output every letter in a sentence like:
))
111
3333
etc.
For the string "aB)a2a2a2)" the output is correct:
))
222
B
aaaa
For the string "aB)a2a2a2" the output is wrong:
)
222
)
aaaa
I feel like all my bases are covered but I'm not sure what's wrong with this code.
When you do list.index(x), you're searching the list for the first index that value appears. That's not actually what you want though, you want the specific index of the value you just read, even if the same value occurs somewhere else earlier in the list too.
The best way to get indexes along side values from a sequence is with enuemerate:
for i, x in enumerate(list):
if x >= 1:
print(chr(i) * x)
That should get you the output you want, but there are several other things that would make your code easier to read and understand. First of all, using list as a variable name is a very bad idea, as that will shadow the builtin list type's name in your namespace. That makes it very confusing for anyone reading your code, and you even confuse yourself if you want to use the normal list for some purpose and don't remember you've already used it for a variable of your own.
The other issue is also about variable names, but it's a bit more subtle. Your two loops both use a loop variable named x, but the meaning of the value is different each time. The first loop is over the characters in the input string, while the latter loop is over the counts of each character. Using meaningful variables would make things a lot clearer.
Here's a combination of all my suggested fixes together:
text = input('What is your sentence? ')
counts = [0]*128
for character in text:
counts[ord(character)] += 1
for index, count in enumerate(counts):
if count >= 1:
print(chr(index) * count)

A simple basic Python3 question which I don't Understand

Question:
Fill in the function body for the Python3 function longestWord (you should leave the function header as it appears).
The function takes a single input argument which we assume is a list of strings, with each string forming one English word. The output should be a word from the list which has the greatest number of letters.
You must use a for loop to write this function.
Answer:
def longestWord(listOfWords):
biggestWord = listOfWords[0]
biggestNum = len(biggestWord)
for word in listOfWords:
num = len(word)
if num>biggestNum:
biggestNum=num
biggestWord=word
return biggestWord
print(longestWord(["Hello", "Goodbye"]))
I understand the first three lines. It takes the first value in the list and saves the length of the word inputted. However i don't understand the rest of the code. How does it compare the two inputted words to output the longest one. What is num and word?. Thank you.
I'd like to inform you that this question is about Python3 and not C++. Anyways, what the code is doing is it's taking the first word and stores it in a variable called biggestWord. and storing the length of biggestWord in a variable called biggestNum. Then for each word in listOfWords, it stores the word in a variable called word and stroing the length of it in variable called num. Then it compares num and biggestNum. If the length of some word i.e. num is bigger than the biggest length up until now, i.e. biggestNum, then it puts num in biggestNum to indicate that that's the biggest number up until now. and puts word in biggestWord replacing the old word. Then it returns the word with the biggest length, i.e. biggestWord.

Is there a built-in in Python 3 that checks whether a character is a "basic" algebraic symbol?

I know the string methods str.isdigit, str.isdecimal and str.isnumeric.
I'm looking for a built-in method that checks if a character is algebraic, meaning that it can be found in a declaration of a decimal number.
The above mentioned methods return False for '-1' and '1.0'.
I can use isdigit to retrieve a positive integer from a string:
string = 'number=123'
number = ''.join([d for d in string if d.isdigit()]) # returns '123'
But that doesn't work for negative integers or floats.
Imagine a method called isnumber that works like this:
def isnumber(s):
for c in s:
if c not in list('.+-0123456789'):
return False
return True
string1 = 'number=-1'
string2 = 'number=0.1'
number1 = ''.join([d for d in string1 if d.isnumber()]) # returns '-1'
number2 = ''.join([d for d in string2 if d.isnumber()]) # returns '0.1'
The idea is to test against a set of "basic" algebraic characters. The string does not have to contain a valid Python number. It could also be an IP address like 255.255.0.1.
.
Does a handy built-in that works approximately like that exist?
If not, why not? It would be much more efficient than a python function and very useful. I've seen alot of examples on stackoverflow that use str.isdigit() to retrieve a positive integer from a string. Is there a reason why there isn't a built-in like that, although there are three different methods that do almost the same thing?
No such function exists. There are a bunch of odd characters that can be part of number literals in Python, such as o, x and b in the prefix of integers of non-decimal bases, and e to introduce the exponential part of a float. I think those plus the hex digits (0-9 and A-F) and sign characters and the decimal point are all you need.
You can put together a string with the right character yourself and test against it:
from string import hex_digits
num_literal_chars = hex_digits + "oxOX.+-"
That will get a bunch of garbage though if you use it to test against mixed text and numbers:
string1 = "foo. bar. 0xDEADBEEF 10.0.0.1"
print("".join(c for c in string1 if c in num_literal_chars))
# prints "foo.ba.0xDEADBEEF10.0.0.1"
The fact that it gives you a bunch of junk is probably why no builtin function exists to do this. If you want to match a certain kind of number out of a string, write an appropriate regular expression to match that specific kind of number. Don't try to do it character-by-character, or try to match all the different kinds of Python numbers.

Convert a string into an integer of its ascii values

I am trying to write a function that takes a string txt and returns an int of that string's character's ascii numbers. It also takes a second argument, n, that is an int that specified the number of digits that each character should translate to. The default value of n is 3. n is always > 3 and the string input is always non-empty.
Example outputs:
string_to_number('fff')
102102102
string_to_number('ABBA', n = 4)
65006600660065
My current strategy is to split txt into its characters by converting it into a list. Then, I convert the characters into their ord values and append this to a new list. I then try to combine the elements in this new list into a number (e.g. I would go from ['102', '102', '102'] to ['102102102']. Then I try to convert the first element of this list (aka the only element), into an integer. My current code looks like this:
def string_to_number(txt, n=3):
characters = list(txt)
ord_values = []
for character in characters:
ord_values.append(ord(character))
joined_ord_values = ''.join(ord_values)
final_number = int(joined_ord_values[0])
return final_number
The issue is that I get a Type Error. I can write code that successfully returns the integer of a single-character string, however when it comes to ones that contain more than one character, I can't because of this type error. Is there any way of fixing this. Thank you, and apologies if this is quite long.
Try this:
def string_to_number(text, n=3):
return int(''.join('{:0>{}}'.format(ord(c), n) for c in text))
print(string_to_number('fff'))
print(string_to_number('ABBA', n=4))
Output:
102102102
65006600660065
Edit: without list comprehension, as OP asked in the comment
def string_to_number(text, n=3):
l = []
for c in text:
l.append('{:0>{}}'.format(ord(c), n))
return int(''.join(l))
Useful link(s):
string formatting in python: contains pretty much everything you need to know about string formatting in python
The join method expects an array of strings, so you'll need to convert your ASCII codes into strings. This almost gets it done:
ord_values.append(str(ord(character)))
except that it doesn't respect your number-of-digits requirement.

I am trying to display variable names and num2str representations of their values in matlab

I am trying to produce the following:The new values of x and y are -4 and 7, respectively, using the disp and num2str commands. I tried to do this disp('The new values of x and y are num2str(x) and num2str(y) respectively'), but it gave num2str instead of the appropriate values. What should I do?
Like Colin mentioned, one option would be converting the numbers to strings using num2str, concatenating all strings manually and feeding the final result into disp. Unfortunately, it can get very awkward and tedious, especially when you have a lot of numbers to print.
Instead, you can harness the power of sprintf, which is very similar in MATLAB to its C programming language counterpart. This produces shorter, more elegant statements, for instance:
disp(sprintf('The new values of x and y are %d and %d respectively', x, y))
You can control how variables are displayed using the format specifiers. For instance, if x is not necessarily an integer, you can use %.4f, for example, instead of %d.
EDIT: like Jonas pointed out, you can also use fprintf(...) instead of disp(sprintf(...)).
Try:
disp(['The new values of x and y are ', num2str(x), ' and ', num2str(y), ', respectively']);
You can actually omit the commas too, but IMHO they make the code more readable.
By the way, what I've done here is concatenated 5 strings together to form one string, and then fed that single string into the disp function. Notice that I essentially concatenated the string using the same syntax as you might use with numerical matrices, ie [x, y, z]. The reason I can do this is that matlab stores character strings internally AS numeric row vectors, with each character denoting an element. Thus the above operation is essentially concatenating 5 numeric row vectors horizontally!
One further point: Your code failed because matlab treated your num2str(x) as a string and not as a function. After all, you might legitimately want to print "num2str(x)", rather than evaluate this using a function call. In my code, the first, third and fifth strings are defined as strings, while the second and fourth are functions which evaluate to strings.

Resources