In the following code, first create a list collection in the loadDataSet () function, and then use the map function to convert it into a set D ,after that,it can only print once and become enpty.Does anyone know what is going on here? thank you.
def loadDataSet():
return [ [ 1, 3, 4 ], [ 2, 3, 5 ], [ 1, 2, 3, 5 ], [ 2, 5 ] ]
if __name__ == '__main__':
myDat = loadDataSet()
D = map( set, myDat )
print("first print: ",list(D))
print("second print: ",list(D))
print("len of D: ",len(list(D)))
i use python 3.5.2 and the output is :
first print: [{1, 3, 4}, {2, 3, 5}, {1, 2, 3, 5}, {2, 5}]
second print: []
len of D: 0
map creates an iterator, that can only be iterated once. The second time you call list, D is already empty since it has been iterated through already.
If you want to iterate through it multiple times, do D=list(map(set, myDat))
The reason is because of the behavior of map() function itself. It returns a generator, which can only be consumed once. This means, map can only execute the function to the list of given inputs once and return the resulting object. After that, the generator is exhausted and cannot be used to generate the same result. Therefore, the practice is to save the return value in a variable if you are going to use it more than once.
Related
I'm wondering if there's a way of getting multiple outputs from a function into a list. I'm not interested in creating a list inside of a function for reasons I'm not going to waste your time going into.
I know how many output variables I am expecting, but only through using the annotations["return"] expression (or whatever you call that, sorry for the noobish terminology) and this changes from case to case, which is why I need this to be dynamic.
I know I can use lists as multiple variables using function(*myList), but I'm interested in if there's a way of doing the equivalent when receiving return values from a function.
Cheers!
Pseudocode:
function():
x = 1
y = 2
return x, y
variables = function()
print(variables[0], " and ", variables[1]
result should be = "1 and 2"
yes, with the unpacking assignments expression ex a,b,c= myfunction(...), you can put * in one of those to make it take a variable number of arguments
>>> a,b,c=range(3) #if you know that the thing contains exactly 3 elements you can do this
>>> a,b,c
(0, 1, 2)
>>> a,b,*c=range(10) #for when you know that there at least 2 or more the first 2 will be in a and b, and whatever else in c which will be a list
>>> a,b,c
(0, 1, [2, 3, 4, 5, 6, 7, 8, 9])
>>> a,*b,c=range(10)
>>> a,b,c
(0, [1, 2, 3, 4, 5, 6, 7, 8], 9)
>>> *a,b,c=range(10)
>>> a,b,c
([0, 1, 2, 3, 4, 5, 6, 7], 8, 9)
>>>
additionally you can return from a function whatever you want, a list, a tuple, a dict, etc, but only one thing
>>> def fun():
return 1,"boo",[1,2,3],{1:10,3:23}
>>> fun()
(1, 'boo', [1, 2, 3], {1: 10, 3: 23})
>>>
in this example it return a tuple with all that stuff because , is the tuple constructor, so it make a tuple first (your one thing) and return it
def addition(n):
return n + n
numbers = (1, 2, 3, 4)
result = map(addition, numbers)
print(list(result))
print(set(result))
print(tuple(result))
Output -
[2, 4, 6, 8]
set()
()
Why is only the print of list is executing correctly, the succeeding set and tuple are printing empty objects?
I think that once you use the map object once, you cannot reuse it. I ran my own tests on IDLE, and I found that if you change the code so that print(set(result)) comes first, this is the output:
{8, 2, 4, 6}
[]
()
I am doing a pattern matching and appending their indices into a list. While appending, i would like to avoid appending any overlapping indices already in the list. I have an example code below that i worked out but do not print exactly what i require.
import re
pat_list=[]
for i in ['ALA', 'AL', 'LA']:
for p in re.finditer(i, 'MALAYALAM'):
if p:
print (i, p.span())
if len(pat_list)==0:
pat_list.append(p.span())
print ('LIST',pat_list)
if len(pat_list) >0:
res=[(idx[0], idx[1]) for idx in pat_list if not p.span()[0] >= idx[0] and
p.span()[0]<= idx[1] or p.span()[1] >= idx[0] and p.span()[1]<= idx[1] ]
print ('RES',res)
What i expect to have in the list is [(1,4), (5,8)] and the rest of the indices should not be added.
For any suggestion or help, i will be very grateful!!
This isn't the most optimized code. But I've implemented it using set so that it can be easily understood what I'm trying to do.
word = 'MALAYALAM'
to_find = ['ALA', 'AL', 'LA']
indices = []
# I am creating list of sets to use the issubset method
for piece in to_find:
for found in re.finditer(piece, word):
indices.append(set(range(found.start(), found.end() + 1)))
# indices: [{1, 2, 3, 4}, {5, 6, 7, 8}, {1, 2, 3}, {5, 6, 7}, {2, 3, 4}, {6, 7, 8}]
non_overlap = []
for left in indices:
for right in indices:
is_subset = False
if left==right:
continue
if left.issubset(right):
is_subset = True
break
# If left is the super-set. i.e. independent of other set
if not is_subset:
non_overlap.append((min(left), max(left)))
# non_overlap: [(1, 4), (5, 8)]
There are definately efficient methods out there. But this is one of the easiest solutions.
I have a problem when adding value inside the nested dictionary using the same keys and the value is always shown the same value, The fact is, i want update the value event the keys is same. This algorithm is the basic of Artificial Fish Swarm Algorithm
# example >> fish_template = {0:{'weight':3.1,'visual':2,'step':1},1:'weight':3,'visual':4,'step':2}}
fish = {}
fish_value = {}
weight = [3.1, 3, 4.1, 10]
visual = [2, 4, 10, 3]
step = [1, 2, 5, 1.5]
len_fish = 4
for i in range(0,len_fish):
for w, v, s in zip(weight, visual, step):
fish_value["weight"] = w
fish_value["visual"] = v
fish_value["step"] = s
fish[i] = fish_value
print("show fish",fish)
I expect the result to be like fish_template, but it isn't. The values for the keys 'weight', 'visual', 'step' are always the same with values of 0, 1, 2, and 3. Any solution?
The issue is with fish[i], you simply created a dict with the same element: fish_value. Python does not generate a new memory for the same variable name, so all your dict keys point to the same value=fish_value, which gets overwritten and all your dict values take the last state of fish_value. To overcome this, you can do the following:
fish = {}
weight = [3.1, 3, 4.1, 10]
visual = [2, 4, 10, 3]
step = [1, 2, 5, 1.5]
len_fish = 4
for i in range(0, len_fish):
fish[i]= {"weight": weight[i], "visual": visual[i], "step": step[i]}
print("show fish", fish)
As #Error mentioned, the for loop can be replaced by this one-liner:
fish = dict((i, {"weight": weight[i], "visual": visual[i], "step": step[i]}) for i in range(len_fish))
Not sure I fully understand what you're trying to do here, but the problem is the last line of your inner for loop. You're looping over i in the main loop, then then inner loop is setting fish[i] multiple times. As a result all your fish_value will look identical.
Because of aliasing; the line fish[i] = fish_value is bad practice, fish_value gets overwritten each time you loop; then fish[i] = fish_value just assigns a shallow copy into fish[i], which is not what you want.
But really you can avoid the loop with a dict comprehension.
Anyway, better coding practice is to declare your own Fish class with members weight, visual, step, as below. Note how:
we use zip() function to combine the separate w,v,s lists into a tuple-of-list.
Then the syntax *wvs unpacks each tuple into three separate values ('weight', 'visual', 'step'). This is called tuple unpacking, it saves you needing another loop, or indexing.
a custom __repr__() method (with optional ASCII art) makes each object user-legible. (Strictly we should be overriding __str__ rather than __repr__, but this works)
Code:
class Fish():
def __init__(self, weight=None, visual=None, step=None):
self.weight = weight
self.visual = visual
self.step = step
def __repr__(self):
"""Custom fishy __repr__ method, with ASCII picture"""
return f'<ยบ)))< ๐ [ Weight: {self.weight}, visual: {self.visual}, step: {self.step} ]'
# define whatever other methods you need on 'Fish' object...
# Now create several Fish'es...
swarm = [ Fish(*wvs) for wvs in zip([3.1, 3, 4.1, 10], [2, 4, 10, 3], [1, 2, 5, 1.5]) ]
# zip() function combines the lists into a tuple-of-list. `*wvs` unpacks each tuple into three separate values ('weight', 'visual', 'step')
# See what we created...
>>> swarm
[<ยบ)))< ๐ [ Weight: 3.1, visual: 2, step: 1 ], <ยบ)))< ๐ [ Weight: 3, visual: 4, step: 2 ], <ยบ)))< ๐ [ Weight: 4.1, visual: 10, step: 5 ], <ยบ)))< ๐ [ Weight: 10, visual: 3, step: 1.5 ]]
# ... or for prettier output...
>>> for f in swarm: print(f)
<ยบ)))< ๐ [ Weight: 3.1, visual: 2, step: 1 ]
<ยบ)))< ๐ [ Weight: 3, visual: 4, step: 2 ]
<ยบ)))< ๐ [ Weight: 4.1, visual: 10, step: 5 ]
<ยบ)))< ๐ [ Weight: 10, visual: 3, step: 1.5 ]
I have a list of integers and want to append data after a certain element in the list. I know about the list function, but when I go to use it in a loop, it appends the same data in the same position x amount of times.
Here is what I have:
lister = [1, 2, 3, 4, 5]
counter = 0
for i in range (len(lister)):
lister.insert(i, "Hello")
print(lister)
When I run it, I get ['Hello', 'Hello', 'Hello', 'Hello', 'Hello', 1, 2, 3, 4, 5].
How would I make it so that when I run it, I get, [Hello, 1 , Hello, 2, ...] and so on?
Small change:
lister.insert(i*2, "Hello")
Your loop first runs, it inserts "Hello" as the first item, so lister becomes: ['Hello', 1, 2, 3, 4, 5].
When it runs the second time, it insert "Hello" as the second item, which is... before the "1", because you added something else in first position. So lister becomes: ['Hello', 'Hello', 1, 2, 3, 4, 5]
etc.
Instead, you must skip an item each time: when you insert the second Hello, you must insert it in third position, not second. And the third hello must be in fifth position. Then seventh, then ninth, etc.
Like this:
for i in range (len(lister)):
lister.insert(i*2, "Hello")
And now, you get this:
['Hello', 1, 'Hello', 2, 'Hello', 3, 'Hello', 4, 'Hello', 5]
However, that's still not exactly what you want. To do what you want, you need one extra change: skip the first item, which you can do by adding in position i*2+1 instead of i*2.
It's happening because once you insert an element in the list, the overall index of all elements in the list gets updated. So you need to account for that when inserting the new element, since old indexes do not hold anymore
# your code goes here
lister = [1, 2, 3, 4, 5]
# Keep a count of elements inserted till now
insert_count = 0
for i in range (1, len(lister)):
# The new position of the element is
# i + the elements inserted till now
lister.insert(i + insert_count, "Hello")
insert_count +=1
print(lister)
# [1, 'Hello', 2, 'Hello', 3, 'Hello', 4, 'Hello', 5]