Map() in python gives output once only - python

I was playing with map() function in Python 3.6.3 when I came across this below situation ::
>>> a = [12, 23, 13, 14, 15, 36]
>>> b = [34, 45, 35, 32, 34, 34]
>>> c = [34, 67, 89, 98, 98, 78]
>>> map(lambda x,y,z:x+y+z, a,b,c )
<map object at 0x0000017DD976EC88>
>>> e=map(lambda x,y,z:x+y+z, a,b,c )
>>> list(e)
[80, 135, 137, 144, 147, 148]
>>> list(e)
[]
My question is that why I cannot get output when I used list(e) second time. It's showing empty list.
Can anyone help me with this?

Because In Python 3, map returns an iterator, which you can only iterate over once. If you iterate over an iterator a second time, it will raise StopIteration immediately, as though it were empty. Thats why you get empty list second time when you call it.
For more info see this question
I hope this helps you! :)

Related

How can I create a random order list and including same numbers?

I want to create five random list but have same and not repeat number from 1-100.
I only know I can remove the number from a list which have all number I want and chose randomly put in to new list:
All_list is a list I save all the list I want to save random number from 1-100
number_list is the list including all number I want but it isn't random
number_list = list(range(1, 101))
for i in range(5):
All_list.append(list)
for a in range(1,101):
random_num = random.choice(number_list)
All_list[i-1].append(random_num)
number_list.remove(random_num)
But in:
All_list[i-1].append(random_num)
The above gives a typeError: descriptor 'append' for 'list' objects doesn't apply to a 'int' object. Why does this happen?
Can anyone help me rewrite this code? I will be appreciative about it.
The quick fix is, when calling All_list.append, to pass an empty list ([]), instead of the class list.
The error message is hard to understand without knowing some details about how methods work. Since All_list contains the class list, the following statement:
All_list[i-1].append(random_num)
is equivalent to:
list.append(random_num)
This grabs the append function from the list class and calls it in a way that treats random_num as the object instead of a list. Python sees that random_num is not an instance of the class where append is defined, so it throws an error.
Of course, you still have another error caused by the inner loop using up all of number_list. I don't know exactly what you're trying to do there.
Create list of random number, and group the random number into chunk_size size sublist.
import random
data = random.sample(range(1,101), 100)
chunk_size=int(len(data)/5)
_chunks=list(data [i:i+chunk_size]
for i in range(0, len(data ), chunk_size))
Output
[[98, 91, 87, 92, 85, 45, 3, 1, 76, 13, 11, 14, 43, 21, 42, 73, 26, 61, 63, 79], [12, 29, 2, 48, 10, 70, 30, 81, 44, 83, 49, 20, 24, 54, 77, 23, 40, 66, 32, 51], [31, 55, 9, 8, 60, 72, 19, 38, 57, 27, 68, 53, 41, 56, 35, 75, 17, 7, 64, 90], [33, 52, 71, 39, 62, 94, 16, 93, 37, 4, 99, 34, 65, 36, 58, 6, 82, 97, 88, 5], [86, 84, 78, 50, 18, 89, 59, 46, 100, 15, 47, 95, 74, 22, 67, 25, 69, 28, 80, 96]]
Your code on line 3 is where the problem is, All_list.append(list). I guess you meant to append number_list in All_list.
Hi #Peggy Lin and Welcome to Stack Overflow.
The error which you mentioned is due to the append function being used with an element of the list which is an integer unless you meant All_list to be a nested list.
Note:
You Should provide a minimal-reproducible-example along with a clear statement regarding what exactly is the problem with your code and also a clear sample output which you intend to get from the corrected code. Refer this to better your question
Please clarify the following points in your problem statement to get better and useful answers:
What type of a list do you require? A nested list containing 5 lists with their random numbers as their elements OR 5 seperate lists with each having random elements as their elements?
but have same and not repeat number from 1-100
Clarify what you meant by this.
I only know I can remove the number from a list which have all number I want and chose randomly put in to new list
This seems to indicate that either you already have a list OR You want to generate the list then modify it. Clarify the statement.
What purpose does number_list serve? What elements do you need in it?
Hope these will guide you in improving your question!

what is most pythonic way to find a element in a list that is different with other elements?

Suppose we have a list with unknown size and there is an element in the list that is different with other elements but we don't know the index of the element. the list only contains numerics and is fetched from a remote server and the length of the list and the index of the different element is changed every time. what is the most pythonic way to find that different element?
I tried this but I'm not sure if it's the best solution.
a = 1
different_element = None
my_list = fetch_list()
b = my_list[0] - a
for elem in my_list[1::]:
if elem - a != b:
different_element = elem
print(different_element)
This is a great use for numpy
Given some random uniform list with a single uniquely different number in it:
>>> li=[1]*100+[200]+[1]*250
If the uniform value is known (in this case 1 and the unknown value is 200) you can use np.where on an array to get that value:
>>> import numpy as np
>>> a=np.array(li)
>>> a[a!=1]
array([200])
If the uniform values are not known, you can use np.uniques to get the counts of uniques:
>>> np.unique(a, return_counts=True)
(array([ 1, 200]), array([350, 1]))
For a pure Python solution, use a generator with next to get the first value that is different than all the others:
>>> next(e for i, e in enumerate(li) if li[i]!=1)
200
Or, you can use dropwhile from itertools:
>>> from itertools import dropwhile
>>> next(dropwhile(lambda e: e==1, li))
200
If you do not know what the uniform value is, use a Counter on a slice big enough to get it:
>>> uniform=Counter(li[0:3]).most_common()[0][0]
>>> uniform
1
>>> next(e for i, e in enumerate(li) if li[i]!=uniform)
200
In these cases, next will short-circuit at the first value that satisfies the condition.
Would this work for you?
In [6]: my_list = [1,1,1,2,1,1,1]
In [7]: different = [ii for ii in set(my_list) if my_list.count(ii) == 1]
In [8]: different
Out[8]: [2]
You can use Counter from collections package
from collections import Counter
a = [1,2,3,4,3,4,1]
b = Counter(a) # Counter({1: 2, 2: 1, 3: 2, 4: 2})
elem = list(b.keys())[list(b.values()).index(1)] # getting elem which is key with value that equals 1
print(a.index(elem))
Another possible solution that just differently compute elem
a = [1,2,3,4,3,4,1]
b = Counter(a) # Counter({1: 2, 2: 1, 3: 2, 4: 2})
elem = (k for k, v in b.items() if v == 1)
print(a.index(next(elem)))
UPDATE
Time consumption:
As #Jblasco mentioned, Jblasco's method is not really efficient one, and i was curious to measure it.
So the initial data is array with 200-400 elements, with only one unique value. The code that generate that array is. At the end of snipped there is 100 first elements that prove that it has one unique
import random
from itertools import chain
f = lambda x: [x]*random.randint(2,4)
a=list(chain.from_iterable(f(random.randint(0,100)) for _ in range(100)))
a[random.randint(1, 100)] = 101
print(a[:100])
# [5, 5, 5, 84, 84, 84, 46, 46, 46, 46, 6, 6, 6, 68, 68, 68, 68, 38,
# 38, 38, 44, 44, 61, 61, 15, 15, 15, 15, 36, 36, 36, 36, 73, 73, 73,
# 28, 28, 28, 28, 6, 6, 93, 93, 74, 74, 74, 74, 12, 12, 72, 72, 22,
# 22, 22, 22, 78, 78, 17, 17, 17, 93, 93, 93, 12, 12, 12, 23, 23, 23,
# 23, 52, 52, 88, 88, 79, 79, 42, 42, 34, 34, 47, 47, 1, 1, 1, 1, 71,
# 71, 1, 1, 45, 45, 101, 45, 39, 39, 50, 50, 50, 50]
That's the code that show us results, i choose to execute 3 times with 10000 executions:
from timeit import repeat
s = """\
import random
from itertools import chain
f = lambda x: [x]*random.randint(2,4)
a=list(chain.from_iterable(f(random.randint(0,100)) for _ in range(100)))
a[random.randint(1, 100)] = 101
"""
print('my 1st method:', repeat(stmt="""from collections import Counter
b=Counter(a)
elem = (k for k, v in b.items() if v == 1)
a.index(next(elem))""",
setup=s, number=10000, repeat=3)
print('my 2nd method:', repeat(stmt="""from collections import Counter
b = Counter(a)
elem = list(b.keys())[list(b.values()).index(1)]
a.index(elem)""",
setup=s, number=10000, repeat=3))
print('#Jblasco method:', repeat(stmt="""different = [ii for ii in set(a) if a.count(ii) == 1]
different""", setup=s, number=10000, repeat=3))
# my 1st method: [0.303596693000145, 0.27322746600111714, 0.2701447969993751]
# my 2nd method: [0.2715420649983571, 0.28590541199810104, 0.2821485950007627]
# #Jblasco method: [3.2133491599997797, 3.488262927003234, 2.884892332000163]
I would try maybe something like this:
newList = list(set(my_list))
print newList.pop()
Assuming there's only 1 different value and the rest are all the same.
There's a little bit of ambiguity in your question which makes it difficult to answer but that's all I could think of optimally.

Why doesn't range() return a list?

I ran into some problems when using the range() function to create lists.
Doing some experimenting, I get the following:
>>> isinstance([], list)
True
>>> isinstance(range(10), list)
False
Also, reading its documentation:
>>> print(range.__doc__)
range(stop) -> range object
range(start, stop[, step]) -> range object
Return a virtual sequence of numbers from start to stop by step.
I currently do have a workaround using list(range()), but the question still remains. What is a virtual sequence of numbers?
A range() object calculates numbers on demand, e.g. when iterated over or when you try to access specific indices:
>>> r = range(2, 80, 3)
>>> len(r)
26
>>> r[15]
47
>>> 42 in r
False
>>> r[:10]
range(2, 32, 3)
It is a sequence because the object supports membership testing, indexing, slicing and has a length, just like a list or a tuple. But, unlike a list or a tuple, it doesn't actually contain all integers in the sequence in memory, making it virtual.
When you call list() on a range() object, you are creating a new sequence containing all the integers that are in the range, but you are now storing all those integers:
>>> r_list = list(r)
>>> r_list
[2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 77]
That's a sequence too, but it takes more memory as all integers are now produced up front, wether you'll use them or not. So a list or a tuple is a concrete sequence.
Using the sys.getsizeof() function, we can calculate how much memory each object uses:
>>> import sys
>>> sys.getsizeof(r)
48
>>> sys.getsizeof(r_list) + sum(sys.getsizeof(i) for i in r_list)
1072
The list object uses 22 times the memory; that's because it contains 26 integer objects.
And to address the comment on your question, range() objects are not iterators. Iterators produce values one by one on demand, but cannot be indexed, they produce all values just once and they do not have a length. You can produce an iterator from a range() object with the iter() function:
>>> iter(r)
<range_iterator object at 0x10aea23f0>
>>> r_iter = iter(r)
>>> len(r_iter)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'range_iterator' has no len()
>>> list(r_iter)
[2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59, 62, 65, 68, 71, 74, 77]
>>> list(r_iter)
[]
but once exhausted, the iterator won't produce the same range again.
All of the above applies mainly to Python 3; in Python 2 the type is called xrange(), where it is more limited in its abilities (it doesn't support slicing and can only handle integers < sys.maxint).

Printing an array of floats in a certain format

I have a problem writing the following arrays to a .txt file.
This is my code:
for i in range(len(my_particles)):
list = []
list.append(my_particles[i].n)
for z in range(len(my_particles[i].neighbours)):
list.append(my_particles[i].neighbours[z])
#for i in range(len(list)):
print >>f, list
f.close()
This is the output:
[0, 2, 20, 91, 114, 127]
[1, 6, 24, 114]
[2, 0, 65, 73, 91, 114]
[3, 71, 91, 120]
[4, 16, 69, 104]
[6, 1, 25, 87, 100, 114]
[7, 19, 83, 111]
[9, 38, 59, 72, 76]
[11, 56, 101, 108]
[12, 86, 92, 126]
[13, 30, 79, 82, 101, 104]
[14, 78, 103, 124]
[15, 23, 44, 90, 116]
[16, 4, 97, 106, 108]
[17, 19, 85, 111]
[18, 47, 60, 68, 74]
Is there a way to print it in this format?
0, 2, 20, 91, 114, 127
1, 6, 24, 114
I have tried
print>>f, "".join(list)
But it does not work, as it is a list of numpy64 floats.
You want to make strings out of each member of the list first. Try
print >>f, ', '.join(map(str,list))
Also, don't name variables list!
Try
",".join(str(i) for i in list))
hacky fix:
print(str(list).replace(']','').replace('[',''))
Converting them to strings should work
print >>f, ', '.join(str(elem) for elem in my_list)
and as Brien said, don't call your list list
If list is a numpy array of floats:
list.astype('str')
OR-You can also use csv to write np.arrays quickly:
import csv
import numpy as np
a = np.random.uniform(0,10,size = (5,5))
writer = csv.writer(open('txtfile.txt','wb'))
writer.writerows(a)
Yields txt file:
3.55183065126,1.05649949199,5.15510365109,1.0369928554,7.66646909667
9.5145737219,1.53877245296,5.53917128683,1.55343228883,8.78227048275
5.80408228776,2.58788175555,0.502704494319,1.63833152952,3.59898531148
2.94430872526,2.42069917781,5.75920106752,2.42453222446,1.73308148034
1.9579612159,0.609573767011,3.87717828624,7.86853109668,7.41038950637
or if you wanted integers, adding:
writer.writerows(a.astype(int))
would yield
2,0,3,4,1
9,5,4,4,3
9,7,6,4,2
3,5,7,2,0
6,0,2,7,7
Firstly, you should use the with statement when dealing with files to ensure they are automatically closed even if the program encounters an error befor they finish. Secondly, you can replace for i in range(len(my_list)) and my_list[i] with for i in my_list and i. Also, having a variable called list overwrites the inbuilt type list. Common practice is to use a trailing underscore to avoid this.
This code should work (although I don't currently have Numpy installed to test it with)
with open("myfilename.txt","w") as f:
for i in my_particles:
list_ = []
list_.append(i.n)
for j in value.neighbours:
list_.append(j)
f.write(", ".join(str(n) for n in list_))
Note that this will erase the previous contents of the file. If you don't want this, open the file with "a" in the open function rather than "w".

add two lists then sort = None(?) [duplicate]

This question already has answers here:
Why do these list methods (append, sort, extend, remove, clear, reverse) return None rather than the resulting list?
(6 answers)
Closed 6 months ago.
Second list squared each item on list, xs. Running the code below, python gives me 'None'
xs = [12, 10, 32, 3, 66, 17, 42, 99, 20]
a = [b**2 for b in xs]
c = (a + xs).sort()
print(c, end=', ')
Same list but different code--
xs = [12, 10, 32, 3, 66, 17, 42, 99, 20]
a = [b**2 for b in xs]
c = a + xs
c.sort()
print(c, end=', ')
...python gives me my list(c), all sorted. I don't get it. Or is there a more pythonic way to do this?
Thanks!
Generally speaking, anything that operates on something in-place will return None, by convention. (This convention is not necessarily always followed, however.) somelist.sort() will sort the list in-place.
If you'd rather have a sorted copy, you can just call c = sorted(a + xs). sorted operates on a copy of the original, and therefore returns the copy.
There's a much more through explanation here: http://wiki.python.org/moin/HowTo/Sorting/
You use generator expressions and itertools to reduce the amount of temporary storage like this
>>> import itertools
>>> xs = [12, 10, 32, 3, 66, 17, 42, 99, 20]
>>> a = (b**2 for b in xs)
>>> c = sorted(itertools.chain(a, xs))
>>> c
[3, 9, 10, 12, 17, 20, 32, 42, 66, 99, 100, 144, 289, 400, 1024, 1764, 4356, 9801]

Categories