Able to retrieve zipped values only once in python? [duplicate] - python

This question already has answers here:
The zip() function in Python 3
(2 answers)
Closed last month.
Created two lists in python and zipped them using zip function and saved them to a variable. Tried to print it to the console and was able to print successfully and when i tried again,empty list is printed.screenshot
Same with tuples.screenshot
Why i am able to retrieve values only once? Am in doing something wrong?
Python 3.7.1

The zip function is actually just an iterator -- an iterator can only be traversed once. If you want to be able to iterate over it multiple times, convert it to a list first.
a = [1,2,3]
b = [1,2,3]
c = list(zip(a, b))

Why is this?
Because those are similar to generators, so you can print first time, but when you try to print it again, it starts from the end, and no values left, see an example (clearer than yours):
>>> l=[1,2,3,4]
>>> it=iter(l) # generator basically (as in your question, zip, is also considered as a geneartor here)
>>> list(it)
[1, 2, 3, 4]
>>> list(it)
[]
>>>
So how to solve this issue?
Simply just replace this line:
zipped_list = zip(list1,list2)
With:
zipped_list = list(zip(list1,list2))
Then everything would work fine.

Related

Python generator function to loop over iterable sequence while eliminating duplicates

I am trying to create a generator function that loops over an iterable sequence while eliminating duplicates and then returns each result in order one at a time (not as a set or list), but I am having difficulty getting it to work. I have found similar questions here, but the responses pretty uniformly result in a list being produced.
I would like the output to be something like:
>>> next(i)
2
>>> next(i)
8
>>> next(i)
4....
I was able to write it as a regular function that produces a list:
def unique(series):
new_series = []
for i in series:
if i not in new_series:
new_series.append(i)
return new_series
series = ([2,8,4,5,5,6,6,6,2,1])
print(unique(series))
I then tried rewriting it as a generator function by eliminating the lines that create a blank list and that append to that list, and then using "yield" instead of "return"; but I’m not getting it to work:
def unique(series):
for i in series:
if i not in new_series:
yield new_series
I don't know if I'm leaving something out or putting too much in. Thank you for any assistance.
Well, to put it simply, you need something to "remember" the values you find. In your first function you were using the new list itself, but in the second one you don't have it, so it fails. You can use a set() for this purpose.
def unique(series):
seen = set()
for i in series:
if i not in seen:
seen.add(i)
yield i
Also, yield should "yield" a single value at once, not the entire new list.
To print out the elements, you'll have to iterate on the generator. Simply doing print(unique([1, 2, 3])) will print the resulting generator object.
>>> print(unique([1, 1, 2, 3]))
<generator object unique at 0x1023bda98>
>>> print(*unique([1, 1, 2, 3]))
1 2 3
>>> for x in unique([1, 1, 2, 3]):
print(x)
1
2
3
Note: * in the second example is the iterable unpack operator.
Try this:
def unique(series):
new_se = []
for i in series:
if i not in new_se:
new_se.append(i)
new_se = list(dict.fromkeys(new_se)) # this will remove duplicates
return new_se
series = [2,8,4,5,5,6,6,6,2,1]
print(unique(series))

Confused about python, lists/generator objects [duplicate]

This question already has an answer here:
Why a generator object is obtained instead of a list
(1 answer)
Closed 3 years ago.
Not sure if this has been asked before but I couldn't find a proper, clear explanation.
I had a concern about something related to python syntax.
While practicing some python, I Intuitively assumed this would print all the elements of the list; list1.
But it doesn't seem to do so, why would that be?
I could obviously print it in many other ways; but I fail to understand the inherent python logic at play here.
list1 = [1,2,3,4]
print(list1[i] for i in range(len(list1)))
I expected the output to be '[1, 2, 3, 4]', but it instead prints a generator object.
You need to surround list1[i] for i in range(len(list)) with [] to indicate that it's a list. Although list1 is a list, you are trying to use a generator expression to print it out, which will return a generator object (type of iterable similar to a list.) Without specifying you want to convert the generator to a list, it won't print a list. (A generator expression converted to a list is called list comprehension.)
Even if you did do this, it would still print it [1, 2, 3, 4] rather than 1 2 3 4. You need to do [print(list1[i], end=" ") for i in range(len(list1)))] for that to work. There are far better ways of doing this: see donkopotamus's answer.
The expression (list1[i] for i in range(len(list))) defines a generator object. So that is what is printed.
If you wish to print a list, then make it a list comprehension rather than a generator, and print that:
print( [list1[i] for i in range(len(list1))] )
Alternatively, you could force evaluation of the generator into a tuple (or list or set), by passing the generator to the appropriate type using eg
print(tuple(list1[i] for i in range(len(list1))))
In order to get the specific output you intended (space separated) of 1 2 3 4 you could use str.join in the following way:
>>> list1 = [1, 2, 3, 4]
>>> print(" ".join(list1[i] for i in range(len(list1))))
1 2 3 4
or unpack the list into print (this will not work in python 2, as in python 2 print is not a function)
>>> print(*(list1[i] for i in range(len(list1))))
1 2 3 4
(list1[i] for i in range(len(list1)))
is indeed a generator object, equivalent to simply
(x for x in list1)
You're passing that generator to print as a single argument, so print simply prints it: it does not extract the elements from it.
Alternatively, you can unpack it as you pass it to print:
print(*(list1[i] for i in range(len(list1))))
This will pass each element of the generated sequence to print as a separate argument, so they should each get printed.
If you simply meant to print your list, any of the following would have worked:
print(list1)
print([list1[i] for i in range(len(list1))])
print([x for x in list1])
The use of square brackets makes a list comprehension rather than a generator expression.
There is something called list comprehension and generator expression in python. They are awesome tools, you can find more info by googling. Here is a link.
Basically, you can make a list on the fly in python.
list1 = [1,2,3,4]
squared_list = [i*i for i in list1]
would return a list with all the items squared. However, is we say
squared_gen_list = (i*i for i in list1)
this returns what is known as a generator object. That is what is happening in your case, as you can see from the syntax and so you are just printing that out. Hope that clears up the confusion.

Python list not appending [duplicate]

This question already has answers here:
Quickly append value to a list [closed]
(4 answers)
Closed 4 years ago.
I've been following a tutorial exactly but my list isn't appending--I get the error, "AttributeError: 'list' object attribute 'append' is read-only."
My code is:
mylist = [1,2,3]
mylist.append = (4)
Thank you in advance.
mylist = [1,2,3]
mylist.append = (4) # Wrong!!
append is a method that is used to add an element to an existing list object. If the object contains 3 elements and you wish to append a new element to it, you can do it as follows:
mylist.append(4)
There is something very important to note here. Whenever you do something like this:
mylist = [] # or mylist = list()
You are creating an object of type list. Hence, if you are familiar with OOP concepts, append is a member function of the class. To further verify this, you can do something like this: (Using Python 3.7)
>>> a = []
>>> type(a)
<class 'list'>
Welcome to programming!
Append is a (read-only) function. You don't assign to it, you call it.
mylist.append(4)
is what you're looking for!
append is a function so use mylist.append(4) and it should work fine.
append is an attribute of List. If you want to append an item to your list use append as a function.
mylist = [1, 2, 3]
mylist.append(4)
print(mylist)
>> [1, 2, 3, 4]
what you are currently doing it you are trying to override the append function to be = 4
append is function it takes the argument which you want to append:
e.g.
.append()

Python dictionary, lists ,join and Interpreter [duplicate]

This question already has answers here:
Why is the order in dictionaries and sets arbitrary?
(5 answers)
Closed 5 years ago.
join in python joins the list elements and keys in dictionaries right?.
Whenever I use join to join a list the output is in the same order as the list. I know it not ordered and the output clearly differed when i gave the same in a file and in the interpreter.
My question is how interpreter remembers that and gives the same output everytime for that order. Is it in some sort of cache or??
>>> x = ['a','b','c']
>>> ','.join(x)
'a,b,c'
>>> x = ['c','b','a']
>>> ','.join(x)
'c,b,a'
using a dict
>>> z = {'a':3,'b':1,'c':4,'d':2}
>>> ','.join(z)
'b,d,a,c'
>>> z = {'a':3,'d':1,'c':4,'b':2}
>>> ','.join(z)
'c,d,a,b'
So I concluded that it varies each time but when I give the same dictionary with a specific order after several instructions it still displays the output in some order which is the same everytime in the interpreter!
>>> z = {'foo':3,'bar':1,'egg':4,'spam':2}
>>> ','.join(z)
'egg,bar,foo,spam'
>>> z = {'bar':3,'foo':1,'egg':4,'spam':2}
>>> ','.join(z)
'egg,bar,foo,spam'
>>> z = {'bar':3,'foo':1,'spam':4,'egg':2}
>>> ','.join(z)
'spam,bar,foo,egg'
>>> z = {'foo':3,'bar':1,'egg':4,'spam':2}
>>> ','.join(z)
'egg,bar,foo,spam'
I maybe missing something out but how does the interpreter remember it. Clear explanations would help greatly.
NOTE: As seen in the comments mentioned by chris_rands
I quote 'the dict iteration is fixed within an interpreter session because the environmental variable PYTHONHASHSEED is fixed'
is more along the lines of the answer I am looking for. Explanations would be great!.
dictionaries dont have an order in python. You might randomly get the same order, but it's not guaranteed. If you need a dictionary with a fixed order, have a look at OrderedDict: https://docs.python.org/2/library/collections.html#collections.OrderedDict
You can use sortedcontainers, and then join
from sortedcontainers import SortedDict
z={'egg': 4, 'foo': 3, 'bar': 1, 'spam': 2}
','.join(SortedDict(z))
#'bar,egg,foo,spam'
in natural case :
','.join(dict(SortedDict(z))) #or ','.join(z)
#'egg,foo,bar,spam'

append function in python [duplicate]

This question already has answers here:
Ellipsis lists [...] and concatenating a list to itself [duplicate]
(3 answers)
Closed 6 years ago.
I have a list X = ['xyz']
I use the below commands for appending to another variable.
L = X
L.append(X)
L
Out[109]: ['xyz', [...]]
I am unable to understand why the second element in the new L list is not having the value as 'xyz'
My question is not how to append or extend a list, but in fact about the functionality of Append function, which has been correctly explained by #sinsuren below.
append add X as an element to L. If you want the element inside X to be inserted to L, use extend instead:
>>> X = ['xyz']
>>> L = X
>>> L.extend(X)
>>> L
['xyz', 'xyz']
Try this, it will extend the list.
L.extend(X)
But if you want to use append. Use a element like this L.append('abc'). It will give same result or L.append(X[0])
Edit: You have Appended list to itself. It will recursively append to itself and due to which even L[1] will give you same response. Like L[1] = ['xyz', [...]] . and for more understanding Please refer What's exactly happening in infinite nested lists?

Categories

Resources