hello I am kind of confused about the max() function, I have the following code:
a = '9:30'
b = '10:44'
c = '8:22'
x = max(a, b, c)
print (x)
so my question is: why does this return 9:30? and if I were to delete the a from inside max it would return 8:22
String a compares as the biggest because it starts with 9 and the other strings start with 1 and 8. Python therefore returns '9:30' as the maximum value out of those three strings.
As you are doing string comparison the int or ASCII value of '9' is greater than '8' and '1'. You can see the int value of individual char using ord built-in function.
>>> ord('9')
57
>>> ord('1')
49
>>> ord('8')
56
And as Python does comparison in lexicographical manner(from left to right each char). It finds value of '9' greater. And if you delete '9' if finds '8''s value greater than '1'.
One way to achieve could be :-
a = '9:30'
b = '10:44'
c = '8:22'
d = '10:55'
print max([a, b, c, d], key=lambda x: map(int, x.split(':')))
Its because of that max function will find the max value lexicographicaly , you can use a proper key for max function to convert the hour and min to int.
>>> l=[a,b,c]
>>> max(l,key=lambda d :map(int, d.split(":")))
'10:44'
Since it's arguments are strings, it is returning the string that is latest in alphabetic order.
it is comparing strings, and, as such, it starts by comparing the first character, and then, if that character is the same, moves on to the next and then the next etc etc.
So '9:30' is returned because 9 > 8 > 1. If you want "10:44" to return, then you should use the datetime module, unless you want to write custom code for that
edit: and sniped by people who type faster!
You are comparing strings, not numbers or times. As such, it compares the strings by their first character (and if those are equal, by the second, and so on), and the first character of "9:30" is the highest.
If you want to compare the times, you can split the string at the :symbol, map the parts to integers and compare those, using an according key function.
x = max([a, b, c], key=lambda s: map(int, s.split(":")))
Here's another way to do it so you can just use the regular max function. First, pad the strings so that "9" becomes "09" and "10" stays "10". You can use str.zfill for this:
a = '9:30'
b = '10:44'
c = '8:22'
a, b, c = map(lambda s: s.zfill(5), (a, b, c))
Now, they will be what you want lexicographically!
print(max([a, b, c]))
10:44
You only have to pad them once, but you will be stuck with:
print(min([a, b, c]))
08:22
Related
I'm interested in how is Python handling slicing where the stop attribute is larger than the length of the string we are working with, for example:
my_string = 'abc'
my_slice = my_string[:10]
I am aware that my_slice == 'abc', what interests me is how efficient this is and how it works under the hood.
I've read Time complexity of string slice and Understanding slice notation, but didn't find the exact case I was looking for.
My guess based on mentioned sources would be that a shallow copy of the string is returned (my_string[:10] is the same as my_string[:] in this case), is this the case?
The logic of python is that it will extract all the values that are before that index in the list.
So if the stop value is higher than the length of the list it will return the whole list because all the values' indexes are under the stop number, so it will extract all the values.
Slicing in Python follows the following format:
myVar[fromIndex:toIndex]
The end of the slicing marked by the toIndex, counts to its index, which is one character less:
my_string = 'abc'
print(my_string[2]) #Output: 'c'
print(my_string[:2]) #Output: 'ab'
If we set a final index greater than the length of characters of the data, it will take it entire (it prints from the first value to the last one found). For example (following the example you have given):
0 1 2 3
a b c
my_string = 'abc'
print(my_string[:len(my_string)]) #Output: 'abc'
With the following example, you can clearly see that [:] (being the full length of the string) is equivalent to printing the value by slicing from the beginning to the end of the string:
0 1 2
a b c
my_string = 'abc'
print(my_string[:]) #Output: 'abc'
0 1 2 3
a b c
my_string = 'abc'
print(len(my_string)) #Output: '3'
print(my_string[:len(my_string)]) #Output: 'abc'
I am starting to learn Python and looked at following website: https://www.w3resource.com/python-exercises/string/
I work on #4 which is "Write a Python program to get a string from a given string where all occurrences of its first char have been changed to '$', except the first char itself."
str="restart"
char=str[0]
print(char)
strcpy=str
i=1
for i in range(len(strcpy)):
print(strcpy[i], "\n")
if strcpy[i] is char:
strcpy=strcpy.replace(strcpy[i], '$')
print(strcpy)
I would expect "resta$t" but the actual result is: $esta$t
Thank you for your help!
There are two issues, first, you are not starting iteration where you think you are:
i = 1 # great, i is 1
for i in range(5):
print(i)
0
1
2
3
4
i has been overwritten by the value tracking the loop.
Second, the is does not mean value equivalence. That is reserved for the == operator. Simpler types such as int and str can make it seem like is works in this fashion, but other types do not behave this way:
a, b = 5, 5
a is b
True
a, b = "5", "5"
a is b
True
a==b
True
### This doesn't work
a, b = [], []
a is b
False
a == b
True
As #Kevin pointed out in the comments, 99% of the time, is is not the operator you want.
As far as your code goes, str.replace will replace all instances of the argument supplied with the second arg, unless you give it an optional number of instances to replace. To avoid replacing the first character, grab the first char separately, like val = somestring[0], then replace the rest using a slice, no need for iteration:
somestr = 'restart' # don't use str as a variable name
val = somestr[0] # val is 'r'
# somestr[1:] gives 'estart'
x = somestr[1:].replace(val, '$')
print(val+x)
# resta$t
If you still want to iterate, you can do that over the slice as well:
# collect your letters into a list
letters = []
char = somestr[0]
for letter in somestr[1:]: # No need to track an index here
if letter == char: # don't use is, use == for value comparison
letter = '$' # change letter to a different value if it is equal to char
letters.append(letter)
# Then use join to concatenate back to a string
print(char + ''.join(letters))
# resta$t
There are some need of modification on your code.
Modify your code with as given in below.
strcpy="restart"
i=1
for i in range(len(strcpy)):
strcpy=strcpy.replace(strcpy[0], '$')[:]
print(strcpy)
# $esta$t
Also, the best practice to write code in Python is to use Function. You can modify your code as given below or You can use this function.
def charreplace(s):
return s.replace(s[0],'$')[:]
charreplace("restart")
#'$esta$t'
Hope this helpful.
I am new to python and I have really poor expiriences with other codes.
For the most of you a stupid question but somewhere I should start.
def fib(n):
a, b = 0, 1
while a < n:
print(a, end=' ')
a, b = b, a+b
print()
I don't understand why one should enter a, b = b, a+b
I see and understand the result and I can conclude the basic algorithm but I don't get the real understanding of what is happening with this line and why we need it.
Many thanks
This line is executed in the following order:
New tuple is created with first element equal to b and second to a + b
The tuple is unpacked and first element is stored in a and the second one in b
The tricky part is that the right part is executed first and you do not need to use temporary variables.
The reason you need it is because, if you update a with a new value, you won't be able to calculate the new value of b. You could always use temporary variables to keep the old value while you calculate the new values, but this is a very neat way of avoiding that.
It's called sequence unpacking.
In your statement:
a, b = b, a + b
the right side b, a + b creates a tuple:
>>> 8, 5 + 8
(8, 13)
You then assign this to the left side, which is also a tuple a, b.
>>> a, b = 8, 13
>>> a
8
>>> b
13
See the last paragraph the documentation on Tuples and Sequences:
The statement t = 12345, 54321, 'hello!' is an example of tuple packing: the values 12345, 54321 and 'hello!' are packed together in a tuple. The reverse operation is also possible:
>>> x, y, z = t
This is called, appropriately enough, sequence unpacking and works for any sequence on the right-hand side. Sequence unpacking requires the list of variables on the left to have the same number of elements as the length of the sequence. Note that multiple assignment is really just a combination of tuple packing and sequence unpacking.
I am looking at adding numbers to a string as python reads through a string.
So if I had a string a = "253+"
I would then have an empty string b.
So, how would I have python read the 2, add it to string b, then read the 5 and add it to string b, and then add the 5 and add it to string b, when it hits something that isnt an integer though, it stops the function.
then string b would be b = "253"
is there a specific call in an iteration that would ask for integers and then add i to another string?
tl;dr
I want to use an iteration to add numbers from one string to another, which stops when it reaches a non-integer.
string b would be an empty string, and string a would be a="253+"
after the call would be done, strng b would equal b="253"
I know this sounds like a homework question, but its not. If you need anything else clarified, I would be happy to.
Here is a simple method for extracting the digits from a string:
In [13]: a="253+"
In [14]: ''.join(c for c in a if c.isdigit())
Out[14]: '253'
The question is a bit unclear, but is this what you're looking for?
a = "123+"
b=""
for c in a:
try:
int(c)
b = b + c
except ValueError:
print 'This is not an int ' + c
break
Running this results in this b being 123 and breaking on the + character. It sounds like the part that's tricky for you at the moment is the try..except ValueError bit. Not that I don't have to break the loop when a ValueError happens, I could just keep looping over the remaining characters in the string and ignore ones that cannot be parsed into an int
In [201]: import itertools as IT
In [202]: a = "253+9"
In [203]: ''.join(IT.takewhile(str.isdigit, a))
Out[203]: '253'
IT.takewhile will stop at the first character in a which is not a digit.
Another way would be to use a regex pattern. You could split the string on non-digits using the pattern r'\D':
In [208]: import re
In [209]: re.split(r'\D', a, maxsplit=1)[0]
Out[209]: '253'
With the use of the for loop, this is relatively easy. If we use our ASCII knowledge, we know that the ASCII values of the digits range from 48 (which represents 0 as a string) to 57 (which represents 9 as a string).
We can find the ASCII value of a character by using the built in method ord(x) where x is the character (i.e. ord('4') is equal to 52, the integer).
Now that we have this knowledge, it will be easy to add this to our for-loop. We simply make a for-loop that goes from 0 to the length of the string minus 1. In the for loop, we are going to use the iteration that we are on as an index, find the character at that index in our string, and finally check to see if its ord value falls in the range that we want.
This will look something like this:
def method(just_a_variable):
b = ''
for i in range(0, len(a)):
if (#something):
if (#something):
b = b+a[i]
return b
Can you fill in the "#somethings"?
Try this:
a = "i889i" #Initial value of A
b = "" #Empty string to store result into
for each in a: #iterate through all characters of a
if each.isdigit(): #check if the current character is a digit
b += each #append to b if the current character is a digit
else: #if current character is NOT a digit
break #break out of for loop
print b #print out result
Hope this helps!
You can write a generator with a regex and generate them one by one:
>>> import re
>>> s='123+456abc789'
>>> nums=(m.group(1) for m in re.finditer(r'(\d+)', s))
>>> next(nums)
'123'
>>> next(nums)
'456'
>>> next(nums)
'789'
values is an array; eventTokens is a string (first element of values). What does the double assignment do? (What are the values of eventToken1 & eventToken2?)
values = data.split("\x01")
eventTokens = values.pop(0)
eventToken1, eventToken2 = eventTokens
I've done an output task (on the Python source) that resulted in the following:
eventTokens is →☹
eventToken1 is →
eventToken2 is ☹
I concluded that the vars somehow split the initial string. However, if I tried compiling an (apparently) similar thing:
arr = ["some", "elements", "inarray"]
c = arr.pop(0)
a, b = c
print c
print a
print b
It resulted in an exception: ValueError: too many values to unpack .
Note: print is not a parameterized method in the tested environment
Variable unpacking is the Python's ability of multiple variable assignment in a single line. The constraint is that the iterable on right side of the expression have to be the same lenght of the variables on the left side. Otherwise you get a too many or to little values to unpack exception.
If you have a string of size 2 like eventTokens is supposed to be, you can then:
>>>a,b = 'ab'
>>>a
'a'
>>>b
'b'
This is very unsafe code. If somehow eventTokens grows larger than two elements the code will raise an exception an your program will be shut down.
Hope this helps!
Since eventTokens is a string of length two, it can be unpacked into two single character strings:
>>> a, b = 'ab'
>>> a
'a'
>>> b
'b'
However, the number of characters in the string must match the number of variables being unpacked into:
>>> a, b = 'abcd'
ValueError: too many values to unpack
Note that you can unpack into one variable!
>>> a, = 'x'
>>> a
'x'
>>> a, = 'xyz'
ValueError: too many values to unpack
c = arr.pop(0) returns "some" here, but you are trying to assign the value to 2 variables in this step (where are there are 4 literals) hence, a, b = c is failing.
Try this instead
arr = ["some", "elements", "inarray"]
c = arr.pop(0)
a, b = arr
print c
print a
print b