Taking input using for loop in python - python

a,b = int(i) for i in input().split()
Can someone explain why the above code doesn't work?
I understand I can use this to make a list like:
a = [int(i) for i in input().split()]
But why doesn't it work for 2 values? If a runtime exception rises(passing more than 2 values), termination is totally legit. But the shows invalid syntax.

I just checked. These are called Generator Functions. And the code can be modified as:
a,b = (int(x) for x in input().split())
Also, a,b = [int(x) for x in input().split()] also does the same job, but instead it return a list. The list is then iterated and is assigned to the variables at python's end. (Correct me if I am wrong)
Thanks to everyone who answered! :D

Related

Need help understanding a specific type of for loop [duplicate]

This question already has answers here:
What does "list comprehension" and similar mean? How does it work and how can I use it?
(5 answers)
Closed 6 months ago.
I am still relatively new to coding. I've been doing this for less than a year and most of the basics I completely understand now. However, every now and then I come across a type of for loop that I can't get my head around.
It usually goes like this:
x for x in list if x in otherList
I completley understand for loops and if statements. But that particular line of code always confuses me. Would anyone be able to provide a detailed explanation of what actually is happening there, please?
It's called a list comprehension if it's in brackets []:
This:
new_list = [x for x in my_list if x in other_list]
Is equivalent to this:
new_list = []
for x in my_list:
if x in other_list:
new_list.append(x)
If it's in parentheses () it's called a generator:
This:
new_list = (x for x in my_list if x in other_list)
Is sort of equivalent to this:
def foo():
for x in my_list:
if x in other_list:
yield x
new_list = foo()
You might want to read this question and answer to understand more about generators and yielding functions.
This is used within a list comprehension and the if statement acts as a filter.
You may begin with a list of all numbers from 0-9:
mynums = range(10)
But then you might want only the even numbers in a new list:
myevennums=[]
for i in mynums:
if mynums%2 ==0:
myevennums.append(i)
That works but so many keystrokes 😭
So python allows list comprehensions:
myevennums = [i for i in mynums if i%2==0]
The condition could be anything, including membership in another list:
evens_to_20 = list(range(0,21,2))
Then you could create a list with the elements of your list that are also in the other list:
myevennums = [i for i in mynums if i in evens_to_20]
In general, when you see a statement like that you can always expand it as:
Y_comprehension = [i for i in X if condition(i)]
# the same as
Y_loop=[]
for i in X:
if condition(i):
Y_loop.append(i)
assert Y_comprehension == Y_loop
If the condition really is very simple, the list-comprehension is usually the better choice. If it starts to get complicated, you probably want the loop or an intermediate function def condition(item): ...

How do I use slices properly

I have just learned the index and slicing in python. After I learned, I got a good idea to make. The idea briefly is that instead of writing the sequence in the code, I want the user to choose a start and an end and print the result. I have written the code and it showed no problems, but when I ran it, it didn't work :(
So I need help to make it run as I imagined.
`
mystring = "Omar Marouf Zaki"
print("Choose First Number")
x = input()
print("Choose Second Number")
y = input()
print(mystring[x:y])
Convert the Strings to Int.
input() return string so you need to do print(mystring[int(x):int(y)]) to make x and y ints
If you want cleaner code, you could convert your input to an int before assigning it to x and y, like this:
x = int(input())
# ...
y = int(input())
# Now you can use [x:y] without problems becuase both x and y are integers
print(mystring[x:y])

How does python max(list) function work?

I have the following code that doesn't work the way it should.
n = int(input())
arr = map(int, input().split())
num=max(arr)
x=list(set(arr))
print (x)
This returns and empty list "[]".
However, if I remove the num=max[arr] line from the code, it works as expected.
n = int(input())
arr = map(int, input().split())
x=list(set(arr))
print (x)
And the output is a list of all elements without duplicates.
I wanted to use the max() value somewhere else in the program, but it seems to break the list formation. Why does this happen? Is there a basic property of the max function that I'm missing?
Edit: Why are people downvoting this without any answers? I'm fairly new to python and any help would be appreciated. If I made a silly mistake please point that out.
n = int(input()) # unused - why put it in your example?
arr = map(int, input().split()) # returns an iterator
num=max(arr) # consumes the iterator
x=list(set(arr)) # nothing in the iterator anymore
print (x) # prints nothing
Fix:
n = int(input()) # unused - why put it in your example?
arr = set(map(int, input().split())) # returns an set named arr
num=max(arr) # get num as max from set
print (arr) # prints the set named arr
In python 2 map behaved differently - for 3 its an iterator. Once consumed, iterators are "empty". You can see for yourself if you print(type(arr)) for the result of your map operation.
Read: map()
I'm not sure why you need to use map in this case. Another thing is that you will throw errors on your input if the user does not provide a single int since you are trying to convert it. You can take your input, like a string of '1 4 6 23 5', convert it to a list of ints, and then find the max.
n = '1 4 6 23 5'
arr = [int(x) for x in n.split()]
max(arr)

What is a set? And what does "a for a in i" do?

I came across these constructs and I'm not quite sure what they do. Can someone explain?
setx = set([a for a in i])
sety = set([y for y in j])
Code, for context
a = int(input())
for i in range(a):
i = (input())
j = (input())
setx = set([a for a in i])
sety = set([y for y in j])
if setx.intersection(sety) == set():
print("NO")
else:
print("YES")
[a for a in i] is a list comprehension. It's basically a concise way to make a list.
They can be really useful, or they can be source of much unreadable code, or both. The full syntax is
[f(i) for i in iterator if conditional(i)]
examples:
List of squares: [i**2 for i in range(n)]
List of squares not divisible by 5: [i**2 for i in range(n) if i**2 % 5 =! 0]
And as for set: Set is a very useful data type in python. It's basically a dictionary without the values. All elements must be unique and hashable, and sets do not store order, but checking to see if an object is in a set is not dependent on the length of the set.
In this case, your code is probably using sets to make figuring out if the two inputs share any commonalities faster and easier to write.
(Also, finally: Uh, as posted, I don't really know what your code does, but I can be pretty sure it doesn't what it wants to. If I were to rewrite it, it'd be something like
a = int(input())
setx = set() #initializing empty sets
sety = set()
for _ in range(a): #underscore often used when you don't care about what you're iterating over, just that you iterate a certain amount of times.
setx.add(input()) #Previously, you'd just get the last input
sety.add(input()) #I doubt that's what you wanted
if setx.intersection(sety): #no need to compare to empty set. if set() will evaluate as false
print("NO")
else:
print("YES")
)
Set is build-in data type: a collection of unordered unique elements, strong on unique.
For more specifics see the amazing python Docs: For example See [https://docs.python.org/3.5/library/stdtypes.html?highlight=set#set]
So using set() over that list comprehension it is removing duplicates from the list.

python list generation/saving bug

I am trying to make program that prints all the possible combinations for a to zzz. I tried to add a save state feature, and it works fine but there is this bug.
Let's say I interrupted the program when it printed something like e. When I execute the program again, it works fine until z but after z instead of printing aa it prints ba and continues from ba. This happens right after it prints zz too. it prints baa instead of aaa. How can I fix this?
Here is what I did so far:
import pickle,os,time
alphabet="abcdefghijklmnopqrstuvwxyz"
try:
if os.path.isfile("save.pickle")==True:
with open("save.pickle","rb") as f:
tryn=pickle.load(f)
for i in range(3):
a=[x for x in alphabet]
for j in range(i):
a=[x+i for x in alphabet for i in a]
b=a[tryn:]
for k in b:
print(k)
time.sleep(0.01)
tryn+=1
else:
tryn=0
for i in range(3):
a=[x for x in alphabet]
for j in range(i):
a=[x+i for x in alphabet for i in a]
for k in a:
print(k)
tryn+=1
time.sleep(0.01)
except KeyboardInterrupt:
with open("save.pickle","wb") as f:
pickle.dump(tryn,f)
If you're using python2, or python3 as the tag suggests, this exists in the standard library already. See itertools, product py2, and product py3, for a simple way to solve this problem.
for i in range(3):
a=[x for x in alphabet]
for j in range(i):
a=[x+i for x in alphabet for i in a]
b=a[tryn:]
Here's your bug. You skip the first tryn strings of every length, rather than just the first tryn strings. This would be easier to recognize in the output if it weren't for the following:
for k in b:
print(k)
time.sleep(0.01)
tryn+=1
You modify tryn, the number of things you're skipping. When you print out length-2 strings, you skip a number of them equal to the number of length-1 strings. When you print out length-3 strings, you skip a number of them equal to the number of length-2 strings. If tryn were bigger than the number of length-1 strings, you would skip even more.
your problem is almost certainly here:
a=[x for x in alphabet]
for j in range(i):
a=[x+i for x in alphabet for i in a]
Perhaps you shouldn't assign the in-loop value to a, but instead use a different name? Otherwise, you are changing what you use every time through the loop....
Edit: More detail. So, technically user2357112's answer is more correct, but I'm amending mine. The initial answer was just from a quick reading, so the other answer is close to the original intent. But, the original version is inefficient (for more reasons than not using product :), since you are generating the inner loops more than once. So let's walk through why this is a bad idea, as an educational exercise:
Initial algorithm:
for i in range(n):
assign a to alphabet
for j in range(i):
i times, we rewrite a to be all combinations of the current set against the alphabet.
Note that for this algorithm, to generate the length(n) product, we have to generate all previous products length(n-1), length(n-2), ..., length(1). But you aren't saving those.
You'd be better off doing something like this:
sum_list = alphabet[:]
#get a copy
product_list = alphabet[:]
#Are we starting at 0, or 1? In any case, skip the first, since we preloaded it
for i in range(1, n):
# Your existing list comprehension was equivalent here, and could still be used
# it MIGHT be faster to do '%s%s'%(x,y) instead of x+y... but maybe not
# with these short strings
# This comprehension takes the result of the last iteration, and makes the next iteration
product_list = [x+y for x,y in product(product_list, alphabet)]
# So product list is JUST the list for range (n) - i.e. if we are on loop 2, this
# is aaa...zzz. But you want all lengths together. So, as you go, add these
# sublists to a main list.
sum_list.extend(product_list)
Overall, you are doing a lot less work.
Couple other things:
You're using i as a loop variable, then re-using it in the loop comprehension. This is conflicting, and probably not working the way you'd expect.
If this is to learn how to write save/restore type apps... it's not a good one. Note that the restore function is re-calculating every value to be able to get back where it left off - if you could rewrite this algorithm to write more information out to the file (such as the current value of product_list) and make it more generator-like, then it will actually work more like a real-world example.
Here is how I would suggest solving this problem in Python. I didn't implement the save state feature; this sequence is not a really long one and your computer should be able to produce this sequence pretty fast, so I don't think it is worth the effort to try to make it cleanly interruptable.
import itertools as it
def seq(alphabet, length):
for c in range(1, length+1):
for p in it.product(alphabet, repeat=c):
yield ''.join(p)
alphabet="abcdefghijklmnopqrstuvwxyz"
for x in seq(alphabet, 3):
print(x)
If you really wanted to, you could make a one-liner using itertools. I think this is too hard to read and understand; I prefer the above version. But this does work and will be somewhat faster, due to the use of itertools.chain and itertools.imap() rather than a Python for loops.
import itertools as it
def seq(alphabet, length):
return it.imap(''.join, it.chain.from_iterable(it.product(alphabet, repeat=c) for c in range(1, length+1)))
alphabet="abcdefghijklmnopqrstuvwxyz"
for x in seq(alphabet, 3):
print(x)
In Python 3.x you could just use map() rather than itertools.imap().

Categories

Resources