I was having some problems with my code , a statement was giving true when it should've been false
For some reason '6' > '14' was true. I changed them into int s instead of str s and the problem was solved but i was wondering why this has happened in the first place
here's a picture !(http://prntscr.com/o1c7na)!
For comparing strings it compares char by char, the first char '6' has a greater ASCII representation that '1' hence it is bigger.
Here some examples of the behaviour:
>>> "a" > "b"
False
>>> "a" > "aaa"
False
>>> "1" > "2"
False
>>> "12" > "1"
True
>>> "6" > "14"
True
>>> "6" > "1"
True
The ASCII code can be retrieve with ord:
>>> ord("6")
54
>>> ord("1")
49
This happens because the ascii string comparison happens with ascii code comparison of each letter one by one. So in the 1st step 6 is compared to 1 and since 6 is > 1 it returns true.
Related
>>> a=10
>>> print(str(a)[a==10])
0
>>> print(str(a)[a=='10'])
1
>>> print(str(a)[a=='11'])
1
How is the above result of 0 and 1 obtained?
Let's put the print statement aside for a second.
Inside the square brackets, the expression being evaluated results in a boolean.
a==10 is True because a is an int equal to 10 and a=='10' is False because a is not a str with value '10'.
Each of those booleans is implicitly converted to an int because the square brackets are indexing the string. So, True becomes index 1 and False becomes index 0.
The string is indexed. '1' is at index 0 of '10', and '0' at index 1. Notice that what is returned is a string and not an integer, and this is because the result of the whole expression, e.g. str(a)[a==10], is a string in all your examples.
All of this is happening without print() being considered. print() just prints the representation to the screen. 0 the integer and '0' the string look the exact same on the screen. Try using type() to understand this.
This is simply because of indexing in strings
let me explain
when you perform str(a), you are typecasting a into a string and consequentially the 10 to '10' whereby '10' is a string with 2 characters ('1' and '0')
Now if you have a string with 2 characters, the character in the zeroth index is the first one('1') , while in the first index is the second character('0')
i.e
animal = 'cat'
print(animal[0])
>>'c'
print(animal[1])
>>'a'
print(animal[2])
>>'t'
moving on, now inside the square brackets you have boolean statements for which when the value is True the output is 1, when the value is False the output is 0
therefore 10==10 is true which is 1,thus str(a)[a==10] is str(a)[1] which is 0 (the 1st index but 2nd character of '10')
10=='10' is false which is 0
thus str(a)[a=='10'] is str(a)[0] which is 1 (the 0th index but 1st character of '10')
10=='11' is false which is 0
thus same as 2nd case
str(a)[a=='11'] is str(a)[0] which is 1 (the 0th index but 1st character of '10')
a = 10, a is a integer value 10
In print()
10 == 10 is false so it Will print 2nd position of str(a)
which is 0
10 == '10' is true so it Will print 1st position of str(a)
which is 1
Example:
a = 12
print(str(a)[4 == 4]) # output 2
Actual question:
I have a string s and I need to sort it using below 3 criteria. I already have the solution but I need to understand a part of that solution. How is it working?
All sorted lowercase letters are ahead of uppercase letters.
All sorted uppercase letters are ahead of digits.
All sorted odd digits are ahead of sorted even digits.
s="Sa27"
print(*sorted(s, key = lambda x: ( x.isdigit() and int(x)%2==0
, x.isdigit(),x.isupper(),x.islower(),x)), sep = '')
I am getting the expected out from the above code: aS72
The stuff inside the lambda gives tuple of True, false values shown below. I want to know how these tuples are actually determining the order/priority of the element.
(False, False, True, False, 'S')
(False, False, False, True, 'a')
(True, True, False, False, '2')
(False, True, False, False, '7')
I've laid out the differing sections with some printing commentary like this:
s="Sa27"
for x in s:
print( 'first group by if this is an even digit\t' + str(x.isdigit() and int(x)%2==0) + '\n',
'then group by if this is a digit or not\t' + str(x.isdigit()) + '\n' ,
'next group by if this is uppercased\t' + str(x.isupper()) +'\n',
'and last group by if this is lowercased\t' + str(x.islower()) +'\n',
'print the charachter\t\t' + str(x)+'\n\n')
print(*sorted(s, key = lambda x: ( x.isdigit() and int(x)%2==0
, x.isdigit(),x.isupper(),x.islower(),x)), sep = '')
When it's returning that Tuple, you can look at this as sorting it at each level in turn. A False value goes ahead of the True value something like this:
After the first round, "Sa7" were all not even digits, ie False, and while "2" is True. So we sort:
"Sa7" into group_0
"2" into group_1
Next we'll sort on it it's a digit. In group_0 "Sa" are False, while "7" is True. IN group_1 "2" is also True. Let's sort:
"Sa" into group_0_0
"7" into group_0_1
"2" into group_1_1 to keep with the convention.
Next we do the same with upper case, so we get "a" False, "S" True, "7" and "2" False so we'll now have:
"a" into group_0_0_0
"S" into group_0_0_1
"7" into group_0_1_0
"2" into group_1_1_0
For this example string you could stop now.
However, last from your example code, we do the same with lower case, so we get "a" True, "S" False, "7" and "2" False and end up with:
"a" into group_0_0_0_1
"S" into group_0_0_1_0
"7" into group_0_1_0_0
"2" into group_1_1_0_0
You'll notice maps out to your True/False tuples. So you're just sorting on each "row" that you've got there.
How do I go about comparing strings? For example
"a" and "b", since "a" comes before "b" then I would put in a tuple like this("a","b"). For "c" and "b", it would be like this ("b","c")
You can compare strings with the usal comparison operators: =, <>, <, <=, >, >=.
You can also use the compare function, which returns -1 if the first string is less than the second, 1 if the first string is greater than the second, and 0 if they are equal.
# "a" < "b";;
- : bool = true
# "a" > "b";;
- : bool = false
# compare "a" "b";;
- : int = -1
I'm trying to check whether or not all chars in my string are either one of these numbers: 1,2,3,4,5,6,7,8,9,0 OR a decimal point and whether they contain spaces or not. I'm using this piece of code but it's not working and I can't figure out why:
print("Confirming added item")
local validAmountString = true
print(addScreen.amountTxtField.text)
for i = 1, #addScreen.amountTxtField.text do
local c = addScreen.amountTxtField.text:sub(i,i)
print("Char " .. i .. " in the amount textflied is " .. c)
if c == "0" or c == "1" or c == "2" or c == "3" or c == "4" or c == "5" or c == "6" or c == "7" or c == "8" or c == "9" or c == "." then
validAmountString = true
else
validAmountString = false
end
print(validAmountString)
end
if string.gsub(addScreen.nameTxtField.text, "%s+", "") ~= "" and string.gsub(addScreen.amountTxtField.text, "%s+", "") ~= "" and validAmountString == true then
--Proceed...
end
The spaces part is working, but for some reason, when I try to check whether validAmountString == true in my if statement, it stops working. The validAmountString returns the correct boolean value according to my print statement though.
Any help? :)
An easier way to go about this would be string.find
local validAmountString = not addScreen.amountTxtField.text:find( "[^%d%.]" )
I'm afraid I can't tell why validAmountString is not true, but you don't have to compare boolean values.
if (validAmountString) then
--is equivilent to
if (validAmountString == true) then
For checking your strings refer to KingOfGamesYami's answer. He's using something called string patterns btw. Check the Lua reference http://www.lua.org/manual/5.3/manual.html#6.4.1 for details.
"[^%d%.]" matches every character that not a digit or a dot. So if find returns something but nil, your string is invalid
For why your program isn't working as is (in case you want to stick to your complicated way:
You check every character of your string. If it is a number or a dot you asign true, if it's not you asign false.
So let's say you have "12A3" as a string.
Then the final value of validAmountString is true because the last character is a number. So you assign true 2 times, then false for the "A" and after that you asign true again. You mess up your total result.
What you should do here is either assign validAmountString = validAmountString and true, else validAmountString = false so you can never overwrite a false, once set.
The even better and more efficient way would be to simply stop your check once you've hit an invalid character. There is no need to check further characters if you find one invalid.
So simply add a break after validAmountString = false
You do not need the loop to check whether it does or does not have valid characters.
You can simply do tonumber(string). It will return nil if there is any character other than a digit in the string.
The documentation for str_split in the stringr package states that for the pattern argument:
If "" splits into individual characters.
which suggests it behaves the same as strsplit in this regard. However,
library(stringr)
str_split("abcab","")
[[1]]
[1] "" "a" "b" "c" "a" "b"
with a leading empty string. This compares with,
strsplit("abcab","")
[[1]]
[1] "a" "b" "c" "a" "b"
Leading empty strings seems to be normal behavior when splitting on non-empty strings,
strsplit("abcab","ab")
[[1]]
[1] "" "c"
but even then, str_split generates an 'extra' trailing empty string:
str_split("abcab","ab")
[[1]]
[1] "" "c" ""
Is this discrepancy a bug, feature, an error in the documentation or just a different notion of what's 'expected behavior'?
If you use commas as delimiters, the "expected" (your mileage may vary) result is more obvious:
# expect "" "2" "3" "4" ""
strsplit(",2,3,4,", ",")
# [[1]]
# [1] "" "2" "3" "4"
str_split(",2,3,4,", ",")
# [[1]]
# [1] "" "2" "3" "4" ""
If I have n commas then I expect (n+1) elements to be returned. So I prefer the results from str_split. However, I wouldn't necessarily call this a bug in strsplit, since in performs as advertised:
(from ?strplit) Note that this means that if there is a match at the beginning of
a (non-empty) string, the first element of the output is ‘""’, but
if there is a match at the end of the string, the output is the
same as with the match removed.
"" is trickier, as there is no way to count the number of times "" appears in a string. Therefore treating it as a special case seems justified.
(from ?str_split) If ‘""’ splits into individual characters.
Based on this I suggest you have found a bug and should take hadley's advice and report it!