Why is i in my code not considered an integer? - python

Im new to Python and am trying to write a function that returns the amount of 1s in a binary number (i.e if the input is 12, then it should return 2, since 12 is 1100 in binary. However I keep getting the error "TypeError: list indices must be integers, not str" and I don't know whats wrong, I have googled the problem but havent understood what the answers meant.
Heres the code (I know it could be shorter I'm just asking the question because I get this error often and don't know why it comes):
def count_ones(num):
x=0
for i in bin(num):
if list(bin(num))[i] ==1:
x += 1
return x

Simply, bin(x) returns a string representing the binary number, as the docs point out.
So for i in bin(num): iterates over the characters in that string.
You can achieve what you want by checking if i == '1' instead, so your code would be
def count_ones(num):
x=0
for i in bin(num):
if i == '1':
x += 1
return x
Consider simplifying your function, however, by using the count method to count the occurrences of '1' in the binary representation, as follows:
def count_ones(num):
return bin(num).count('1')

bin returns a string, where you are iterating over each bit as a string. You should use int(i). You should probably use format or str.format to remove the 0b prefix as b is not an integer.
for i in format(num, 'b'):

I would just use a generator expression for this.
def count_ones(num):
return sum(1 for digit in bin(num) if digit == '1')
Example
>>> count_ones(50)
3
>>> bin(50)
'0b110010'
For what it's worth, the reason your code is not working is that bin returns a string, so each element you loop over will by of type str not int.

Related

Python for iteration with previous variable

the function is meant to do the follow, "to get the n (non-negative integer) copies of the first 2 characters of a given string. Return the n copies of the whole string if the length is less than 2."
Can anyone tell me what does the substr do in line 12?
I get how it works previously on line 8 (when string is larger than 2), but it looses me on how it works on line 12, where the string is lower than 2.
def substring_copy(str, n):
"""
Method 2
"""
f_lenght = 2
if f_lenght > len(str): # If strings length is larger than 2
f_lenght = len(str) # Length of string will be len(str)
substr = str[:f_lenght] # substr = str[:2] (slice 0 y 1)
# If length is shorter than 2
result = ""
for i in range(n):
result = result + substr
return result
print ("\nMethod 2:")
print(substring_copy('abcdef', 2))
print(substring_copy('p', 3));
If the length of p is 1, then isn't it a case that substr isn't that important and the for loop will run 3 (thanks to 3* in the last line of code)?
Thanks in advance!
I think I got it, substr is important for if there are more than 2 characters in the string. When there are less than 2, substr could have a value of 200; the p string would still be just one p and that would concatenate n times (3 times in this example).
So as you inferred substr is just the substring of length 2 (or less) from the original, which can be the input itself if it's already 2 or less.
It's your "duplication target", basically.
Though I do want to point out that the entire thing is a rather bad style, it is over-complicated and doesn't make good use of python:
str is the python string type (which also acts as a conversion function), it's a builtin, shadowing builtin is a bad idea and str is a common builtin, naming a variable str is terrible style, sometimes it's justifiable, but not here
python slicing is "bounded" to what it's slicing, so e.g. "ab"[:5] will return "ab", unlike regular indexing it does not care that the input is too short, this means the entire mess with f_lenght is unnecessary, you can just
substr = s[:2]
Python strings have an override for multiplication, str * n repeats the string n times, this also works with lists (though that is more risky because of mutability and reference semantics)
So the entire function could just be:
def substring_copy(s, n):
return s[:2] * n
The prompt is also not great because of the ambiguity of the word "character", but I guess we can let that slide

sort algorithm implemented in Python has problem

I want to sort Strings in ascending order.
For example, s = 'Zbcdefg' returns answer 'gfedcbZ'
def solution(s):
answer = ''
while True:
max = s[0]
for j in range(1,len(s)):
if ord(max) < ord(s[j]):
max = s[j]
answer += max
s= s.replace(max,'')
if len(s) == 1:
answer += s[0]
break
return answer
This is my code but some test cases are not solved with this. I don't know why. Can you find any logical error in this code?
The problem of this code was in s = s.replace(max,''). If a character searched as a highest order is stored as max (even though the name is not that proper bcz it can overwrite built in func) and pop it out from the original string s using s.replace(max,''), the problem is that method can delete the unexpected character(s) which is the same as max but not the max that I found.
Therefore, I fixed it as s.replace(max,'',1) to replace only one character firstly matched in string s.

What is the star (*) doing in this FizzBuzz solution?

Learning programming in Python and I am doing some challenges. I've run into something I haven't learned yet and was curious what this code is doing.
So my challenge is called the "FizzBuzz" challenge. The instructions are simple:
Create a function that takes a number as an argument and returns
"Fizz", "Buzz" or "FizzBuzz".
If the number is a multiple of 3 the output should be "Fizz". If the
number given is a multiple of 5, the output should be "Buzz". If the
number given is a multiple of both 3 and 5, the output should be
"FizzBuzz". If the number is not a multiple of either 3 or 5, the
number should be output on its own.
I wrote this code to solve it (obviously it can be better):
def fizz_buzz(num):
if num % 3 == 0 and num % 5 == 0:
return 'FizzBuzz'
elif num % 3 == 0:
return 'Fizz'
elif num % 5 == 0:
return 'Buzz'
else:
return str(num)
But, once I submitted my solution I was able to see the top solution, which is:
def fizz_buzz(num):
return "Fizz"*(num%3==0) + "Buzz"*(num%5==0) or str(num)
My question is what is the * doing here? Can someone point me to documentation or resources that addresses what this persons code has done? I don't find it super readable but it is apparently the best solution to the problem.
bool in Python is a subclass of int; True has the value 1, False, 0.
Sequences (including str) in Python can be multiplied, to get the sequence repeated that many times, so:
"Fizz"*(num%3==0)
multiplies "Fizz" by 1 (numeric value of True) when num % 3 == 0, producing the original string, and by 0 (numeric value of False) otherwise, producing the empty string.
The same work is done with "Buzz" and concatenated. If both of them produced the empty string (which is falsy), then the or means str(num) is evaluated and returned (Python's or and and don't evaluate to strict True or False, they evaluate to the last item evaluated, and short-circuit, so or always evaluates to the first truthy item, or the last item in the or chain regardless of truthiness).
Firstly, shorter doesn't always mean better. In this case, your solution is fine, and the "top solution" is clever, but needlessly confusing, as you're aware :P
The star is doing string multiplication, and it's exploiting the fact that False == 0 and True == 1. So if num is divisible by 3, you get 'Fizz' once, and if num is divisible by 5, you get 'Buzz' once. Otherwise you get an empty string, '', and because an empty string is falsy, the or clause means it will be replaced by str(num).
The * is string multiplication as usual. It's just multiplying by 0 or 1 based on whether the condition to print the phrase is met. If neither condition is met, it defaults to returning the number, as it should.
I don't know about a resource, but I can tell you what it does. The phrase num%3==0 is a Boolean which is true if the number is divisible by 3. If that's the case, this phrase returns a 1 (or 0 if False). Same for num%5==0 and divisible by 5. This is then being multiplied by the string Fizz and/or Buzz and concatenated together, where multiplying by 1 returns the string and 0 nothing. If neither of those holds, it returns str(num).
I do not know the link to any documentation or resource about it, but I can explain it to you.
Firstly in python str can be multiplied by a number, for instance 'Fizz' * 3 will return 'FizzFizzFizz' or 'Fizz' * 0 will return '', an empty string.
Secondly bool in python can be also recognized as int, i.e. True is 1 and False is 0.
Thirdly in python strings can be added e.g. 'Fizz'+'Buzz' will return 'FizzBuzz'
What the best solution guy does is very simple by num%3==0 he gets bool and just multiplies the str 'Fizz' or 'Buzz' by it and returns.

how to check each letter in a string and do some action, in Python

So I was messing around in python, and developed a problem.
I start out with a string like the following:
a = "1523467aa252aaa98a892a8198aa818a18238aa82938a"
For every number, you have to add it to a sum variable.Also, with every encounter of a letter, the index iterator must move back 2. My program keeps crashing at isinstance(). This is the code I have so far:
def sum():
a = '93752aaa746a27a1754aa90a93aaaaa238a44a75aa08750912738a8461a8759383aa328a4a4935903a6a55503605350'
z = 0
for i in a:
if isinstance(a[i], int):
z = z + a[i]
elif isinstance(a[i], str):
a = a[:i] + a[(i+1):]
i = i - 2
continue
print z
return z
sum()
This part is not doing what you think:
for i in a:
if isinstance(a[i], int):
Since i is an iterator, there is no need to use a[i], it will confuse Python.
Also, since a is a string, no element of it will be an int, they will all be string. You want something like this:
for i in a:
if i.isdigit():
z += int(i)
EDIT: removing elements of an iterable while iterating over it is a common problem on SO, I would recommend creating a new string with only the elements you wan to keep:
z = 0
b = ''
for i in a:
if i.isdigit():
z += int(i)
b += str(i)
a = b # set a back to b so the "original string" is set to a string with all non-numeric characters removed.
You have a few problems with your code. You don't seem to understand how for... in loops work, but #Will already addressed that problem in his answer. Furthermore, you have a misunderstanding of how isinstance() works. As the numbers are characters of a string, when you iterate over that string each character will also be a (one-length) string. isinstance(a[i], int) will fail for every character regardless of whether or not it can be converted to an int. What you actually want to do is just try converting each character to an int and adding it to the total. If it works, great, and if not just catch the exception and keep on going. You don't need to worry about non-numeric characters because when each one raises a ValueError it will simply be ignored and the next character in the string will be processed.
string = '93752aaa746a27a1754aa90a93aaaaa238a44a75aa08750912738a8461a8759383aa328a4a4935903a6a55503605350'
def sum_(string):
total = 0
for c in string:
try:
total += int(c)
except ValueError:
pass
return total
sum_(string)
Furthermore, this function is equivalent to the following one-liners:
sum(int(c) for c in string if c.isdigit())
Or the functional style...
sum(map(int, filter(str.isdigit, string)))

python, encryption of any size code with a smaller key

So I'm trying to work to create a program which can take two inputs such as
encrypt('12345','12')
and it will return
'33557'
where the code ('12345') and been incremented by the key ('12'), working from right to left.
I have already created one which will work for when the code and key are both 8 long, but I cannot work out how to do this should the code be allowed to be any size, possibly with nested for statments?
Here is the one i did early so you can see better what i am trying to do
def code_block(char,charBlock):
if len(char) == 8 and len(charBlock) == 8: #Check to make sure both are 8 didgets.
c = char
cB = charBlock
line = ""
for i in range(0,8):
getDidget = code_char2(front(c),front(cB))
c = last(c)
cB = str(last(cB))
line =line + getDidget
print(line)
else:
print("Make sure two inputs are 8 didgets long")
def front(word):
return word[:+1]
def last(word):
return word[+1:]
Some code tested on Python 3.2:
from decimal import Decimal
import itertools
def encrypt(numbers_as_text, code):
key = itertools.cycle(code[::-1])
num = Decimal(numbers_as_text)
power = 1
for _ in numbers_as_text:
num += power * int(next(key))
power *= Decimal(10)
return num
if __name__ == "__main__":
print(encrypt('12345','12'))
Some explanation:
code[::-1] is a cool way to reverse a string. Stolen from here
itertools.cycle endlessly repeats your key. So the variable key now contains a generator which yields 2, 1, 2, 1, 2, 1, etc
Decimal is a datatype which can handle arbitrary precision numbers. Actually Python 3's integer numbers would be sufficient because they can handle integer numbers with arbitrary number of digits. Calling the type name as a function Decimal(), calls the constructor of the type and as such creates a new object of that type. The Decimal() constructor can handle one argument which is then converted into a Decimal object. In the example, the numbers_as_text string and the integer 10 are both converted into the type Decimal with its constructor.
power is a variable that starts with 1 is multiplied by 10 for every digit that we have worked on (counting from the right). It's basically a pointer to where we need to modify num in the current loop iteration
The for loop header ensures we're doing one iteration for each digit in the given input text. We could also use something like for index in range(len(numbers_as_text)) but that's unnecessarily complex
Of course if you want to encode text, this approach does not work. But since that wasn't in your question's spec, this is a function focused on dealing with integers.

Categories