Custom class using nested dictionary Python - python-3.x

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 ]

Related

Avoiding overlapping tuples in python while appending to a list

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.

What is this operation in numpy called?

I've been going over the numpy docs looking for a specific operation. The words I would use for this are "overlay" or "mask" but the numpy concepts of those words don't seem to match mine.
I want to take two arrays, one dense and one sparse and combine them thusly:
[ 1, 2, 3, 4, 5 ]
X [ N, N, 10, N, 12 ]
= [ 1, 2, 10, 4, 12 ]
where X is the operation and N is None, or Null, -1, or some other special character.
How is this achieved in numpy/python3?
You can use np.where:
# pick special value
N = -1
dns = [ 1, 2, 3, 4, 5 ]
sprs = [ N, N, 10, N, 12 ]
# this is important otherwise the comparison below
# is not done element by element
sprs = np.array(sprs)
# tada!
np.where(sprs==N,dns,sprs)
# array([ 1, 2, 10, 4, 12])
When called with three arguments m,a,b where "mixes" a and b taking elements from a where m is True and from b where it is False.
You can "fill" the masked array, with np.ma.filled(..) [numpy-doc], for example:
>>> a
array([1, 2, 3, 4, 5])
>>> b
masked_array(data=[--, --, 10, --, 12],
mask=[ True, True, False, True, False],
fill_value=999999)
>>> b.filled(a)
array([ 1, 2, 10, 4, 12])
>>> np.ma.filled(b, a)
array([ 1, 2, 10, 4, 12])
Here we thus fill the masked values from b with the corresponding values of a.

Wrong set output for intervals

I came across an interview question and decided to try it.
The problem is as follows: Given a set of closed intervals, find the smallest set of numbers that covers all the intervals. If there are multiple smallest sets, return any of them.
For example, given the intervals [0, 3], [2, 6], [3, 4], [6, 9], one set of numbers that covers all these intervals is {3, 6}.
My code is below:
def findIntersection(intervals):
"""
find the intersection of a list of intersections.
"""
# First interval
l = intervals[0][0] #lower component
r = intervals[0][1] #higher component
# Check rest of the intervals
# and find the intersection
for i in range(1,len(intervals)):
interval=[l,r]
# If no intersection exists
if (intersecting(intervals[i],interval)):
print()
# Else update the intersection
else:
l = max(l, intervals[i][0])
r = min(r, intervals[i][1])
interval=[l,r]
return([l, r])
def intersecting(x, y):
"""
Return a boolean indicaing if 2 intervals (x,y) are intersecting
"""
return(y[0] > x[1] or x[0] > y[1])
l=[[0, 3], [2, 6], [3, 4], [6, 9]]
print(findIntersection(l) #this does not work
intervals= [ [ 1, 6 ], [ 2, 8 ], [ 3, 10 ], [ 5, 8 ]]
print(findIntersection(intervals))# this works`
For input l: the output is [3,9] which is not the answer. The output with intervals is [5,6] which is expected.
It's not easier to work with the intersection funtion from the set-tool.
like
s1 = set([1,2,3])
s2 = set([2,3,4,5])
print(s1.intersection(s2))

after i print a list, it just despeared

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.

Difference between normal for loop statement and for loop statement inside a list initialization in python [duplicate]

I have the following code:
[x ** 2 for x in range(10)]
When I run it in the Python shell, it returns:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
I've searched and it seems this is called a list comprehension and similarly there seem to be set/dict comprehensions and generator expressions. But how does it work?
From the documentation:
List comprehensions provide a concise way to create lists. Common applications are to make new lists where each element is the result of some operations applied to each member of another sequence or iterable, or to create a subsequence of those elements that satisfy a certain condition.
About your question, the list comprehension does the same thing as the following "plain" Python code:
>>> l = []
>>> for x in range(10):
... l.append(x**2)
>>> l
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
How do you write it in one line? Hmm...we can...probably...use map() with lambda:
>>> list(map(lambda x: x**2, range(10)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
But isn't it clearer and simpler to just use a list comprehension?
>>> [x**2 for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Basically, we can do anything with x. Not only x**2. For example, run a method of x:
>>> [x.strip() for x in ('foo\n', 'bar\n', 'baz\n')]
['foo', 'bar', 'baz']
Or use x as another function's argument:
>>> [int(x) for x in ('1', '2', '3')]
[1, 2, 3]
We can also, for example, use x as the key of a dict object. Let's see:
>>> d = {'foo': '10', 'bar': '20', 'baz': '30'}
>>> [d[x] for x in ['foo', 'baz']]
['10', '30']
How about a combination?
>>> d = {'foo': '10', 'bar': '20', 'baz': '30'}
>>> [int(d[x].rstrip('0')) for x in ['foo', 'baz']]
[1, 3]
And so on.
You can also use if or if...else in a list comprehension. For example, you only want odd numbers in range(10). You can do:
>>> l = []
>>> for x in range(10):
... if x%2:
... l.append(x)
>>> l
[1, 3, 5, 7, 9]
Ah that's too complex. What about the following version?
>>> [x for x in range(10) if x%2]
[1, 3, 5, 7, 9]
To use an if...else ternary expression, you need put the if ... else ... after x, not after range(10):
>>> [i if i%2 != 0 else None for i in range(10)]
[None, 1, None, 3, None, 5, None, 7, None, 9]
Have you heard about nested list comprehension? You can put two or more fors in one list comprehension. For example:
>>> [i for x in [[1, 2, 3], [4, 5, 6]] for i in x]
[1, 2, 3, 4, 5, 6]
>>> [j for x in [[[1, 2], [3]], [[4, 5], [6]]] for i in x for j in i]
[1, 2, 3, 4, 5, 6]
Let's talk about the first part, for x in [[1, 2, 3], [4, 5, 6]] which gives [1, 2, 3] and [4, 5, 6]. Then, for i in x gives 1, 2, 3 and 4, 5, 6.
Warning: You always need put for x in [[1, 2, 3], [4, 5, 6]] before for i in x:
>>> [j for j in x for x in [[1, 2, 3], [4, 5, 6]]]
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'x' is not defined
We also have set comprehensions, dict comprehensions, and generator expressions.
set comprehensions and list comprehensions are basically the same, but the former returns a set instead of a list:
>>> {x for x in [1, 1, 2, 3, 3, 1]}
{1, 2, 3}
It's the same as:
>>> set([i for i in [1, 1, 2, 3, 3, 1]])
{1, 2, 3}
A dict comprehension looks like a set comprehension, but it uses {key: value for key, value in ...} or {i: i for i in ...} instead of {i for i in ...}.
For example:
>>> {i: i**2 for i in range(5)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
And it equals:
>>> d = {}
>>> for i in range(5):
... d[i] = i**2
>>> d
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
Does (i for i in range(5)) give a tuple? No!, it's a generator expression. Which returns a generator:
>>> (i for i in range(5))
<generator object <genexpr> at 0x7f52703fbca8>
It's the same as:
>>> def gen():
... for i in range(5):
... yield i
>>> gen()
<generator object gen at 0x7f5270380db0>
And you can use it as a generator:
>>> gen = (i for i in range(5))
>>> next(gen)
0
>>> next(gen)
1
>>> list(gen)
[2, 3, 4]
>>> next(gen)
Traceback (most recent call last):
File "<input>", line 1, in <module>
StopIteration
Note: If you use a list comprehension inside a function, you don't need the [] if that function could loop over a generator. For example, sum():
>>> sum(i**2 for i in range(5))
30
Related (about generators): Understanding Generators in Python.
There are list, dictionary, and set comprehensions, but no tuple comprehensions (though do explore "generator expressions").
They address the problem that traditional loops in Python are statements (don't return anything) not expressions which return a value.
They are not the solution to every problem and can be rewritten as traditional loops. They become awkward when state needs to be maintained & updated between iterations.
They typically consist of:
[<output expr> <loop expr <input expr>> <optional predicate expr>]
but can be twisted in lots of interesting and bizarre ways.
They can be analogous to the traditional map() and filter() operations which still exist in Python and continue to be used.
When done well, they have a high satisfaction quotient.
If you prefer a more visual way of figuring out what's going on then maybe this will help:
# for the example in the question...
y = []
for x in range(10):
y += [x**2]
# is equivalent to...
y = [x**2 for x in range(10)]
# for a slightly more complex example, it is useful
# to visualize where the various x's end up...
a = [1,2,3,4]
b = [3,4,5,6]
c = []
for x in a:
if x in b:
c += [x]
# \ \ /
# \ _____\______/
# \ / \
# \/ \
# /\ \
# / \ \
# / \ \
c = [x for x in a if x in b]
print(c)
...produces the output [3, 4]
I've seen a lot of confusion lately (on other SO questions and from coworkers) about how list comprehensions work. A wee bit of math education can help with why the syntax is like this, and what list comprehensions really mean.
The syntax
It's best to think of list comprehensions as predicates over a set/collection, like we would in mathematics by using set builder notation. The notation actually feels pretty natural to me, because I hold an undergrad degree in Mathematics. But forget about me, Guido van Rossum (inventor of Python) holds a masters in Mathematics and has a math background.
Set builder notation crash course
Here's the (very basics) of how set builder notation works:
So, this set builder notation represents the set of numbers that are strictly positive (i.e. [1,2,3,4,...]).
Points of confusion
1) The predicate filter in set builder notation only specifies which items we want to keep, and list comprehension predicates do the same thing. You don't have to include special logic for omitting items, they are omitted unless included by the predicate. The empty predicate (i.e. no conditional at the end) includes all items in the given collection.
2) The predicate filter in set builder notation goes at the end, and similarly in list comprehensions. (some) Beginners think something like [x < 5 for x in range(10)] will give them the list [0,1,2,3,4], when in fact it outputs [True, True, True, True, True, False, False, False, False, False]. We get the output [True, True, True, True, True, False, False, False, False, False] because we asked Python to evaluate x < 5 for all items in range(10). No predicate implies that we get everything from the set (just like in set builder notation).
If you keep set builder notation in the back of your mind while using list comprehensions, they're a bit easier to swallow.
HTH!
Introduction
A list comprehension is a high level, declarative way to create a list in Python. The main benefits of comprehensions are readability and maintainability. A lot of people find them very readable, and even developers who have never seen them before can usually guess correctly what it means.
# Snippet 1
squares = [n ** 2 for n in range(5)]
# Snippet 2
squares = []
for n in range(5):
squares.append(n ** 2)
Both snippets of code will produce squares to be equal to [0, 1, 4, 9, 16].
Notice that in the first snippet, what you type is declaring what kind of list you want, while the second is specifying how to create it. This is why a comprehension is a high-level and declarative.
Syntax
[EXPRESSION for VARIABLE in SEQUENCE]
EXPRESSION is any Python expression, but it is typical to have some variable in it. This variable is stated in VARIABLE field. SEQUENCE defines the source of values the variable enumerates through.
Considering Snippet 1, [n ** 2 for n in range(5)]:
EXPRESSION is n ** 2
VARIABLE is n
SEQUENCE is range(5)
Notice that if you check the type of squares you will get that the list comprehension is just a regular list:
>>> type(squares)
<class 'list'>
More about EXPRESSION
The expression can be anything that reduces to a value:
Arithmetic expressions such as n ** 2 + 3 * n + 1
A function call like f(n) using n as variable
A slice operation like s[::-1]
Method calls bar.foo()
...
Some examples:
>>> [2 * x + 3 for x in range(5)]
[3, 5, 7, 9, 11]
>>> [abs(num) for num in range(-5, 5)]
[5, 4, 3, 2, 1, 0, 1, 2, 3, 4]
>>> animals = ['dog', 'cat', 'lion', 'tiger']
>>> [animal.upper() for animal in animals]
['DOG', 'CAT', 'LION', 'TIGER']
Filtering:
The order of elements in the final list is determined by the order of SEQUENCE. However, you can filter out elements adding an if clause:
[EXPRESSION for VARIABLE in SEQUENCE if CONDITION]
CONDITION is an expression that evaluates to True or False. Technically, the condition doesn't have to depend upon VARIABLE, but it typically uses it.
Examples:
>>> [n ** 2 for n in range(5) if n % 2 == 0]
[0, 4, 16]
>>> animals = ['dog', 'cat', 'lion', 'tiger']
>>> [animal for animal in animals if len(animal) == 3]
['dog', 'cat']
Also, remember that Python allows you to write other kinds of comprehensions other than lists:
dictionary comprehensions
set comprehensions

Resources