issue with equating dictionaries and global issue - python-3.x

Trying to figure best way to union of two dictionaries. Here is the code that I have. Counter is one of the options that I found.
def __add__(self,right):
mergedbag = Bag()
mergedbag.bag_value = copy.copy(self.bag_value)
for item in right.bag_value.keys():
mergedbag.bag_value[item] += right.bag_value[item]
return mergedbag

To test if two dictionaries have the same contents, simply use an equality test:
self.bag_items == bag_equal.bag_items
Python does this comparison test efficiently; keys and values have to match exactly and difference in length means the dictionaries are not equal:
>>> a = {'a': 'b'}
>>> b = {'a': 'b'}
>>> a == b
True
>>> b['b'] = 'c'
>>> a == b
False
>>> del b['b']
>>> b['a'] = 'c'
>>> a == b
False
>>> b['a'] = 'b'
>>> a == b
True
Note that rather than raise a TypeError, __eq__ should return the NotImplemented sentinel object to signal that equality testing is not supported:
def __eq__(self, other):
if not isinstance(other, Bag):
return NotImplemented
return self.bag_items == other.bag_items
As a side-note, the in membership operator already returns either True or False, there is no need to use a conditional expression in __contains__; the following is enough:
def __contains__(self, include):
return include in self.bag_items
Your code never actually does anything with the items passed in however, nor are you ever counting the items. Your count() method should just look up the element in self.bag_items and return the count once you properly track counts.

Related

Does Python set update() replace existing items?

If I use my_set.update(my_list) where some elements of my_list are == existing elements in my_set, does it replace the existing items or not?
It does not replace existing elements, as can be seen from the following example:
>>> s = {1}
>>> s.add(1.0)
>>> s
{1}
The same behavior holds for dictionary keys:
>>> d = {1: 'foo'}
>>> d.update({1.0: 'bar'})
>>> d
{1: 'bar'}
It doesn't:
from dataclasses import dataclass
#dataclass(frozen=True)
class MyType:
hashed: int # This will contribute to hash equality
not_hashed: str # This won't contribute to hash equality
# Override hashing/equality
def __eq__(self, other):
return hash(self) == hash(other)
def __hash__(self):
return hash((self.hashed, ))
x = { MyType(hashed=1, not_hashed="original") } # Add an item to a set
x.update([MyType(1, "new")]) # .update() with a different item with the same hash
print(x)
# { MyType(hashed=1, not_hashed='original') } # The original item is in the set

Evaluating the output of multiple functions which return True or False

So I came across this interesting problem.It basically is a lot of functions which return True or False within a function and I want that secondary function to return either True or False based on applying an AND or OR logic to all of the functions within it. I know this is a terrible way to explain so let's see some code which will hopefully explain it better
#this is the first function that return True or False
def f(x):
if x == 1:
return True
elif x == 0:
return False
#this is the function that takes the first one and I want it to return either True or False based on an AND logic
def g(f):
f(1)
f(0)
f(0)
f(1)
f(1)
f(0)
f(1)
Now I know I can just write the second function with 'and' between all the f(x) functions that I call but that seems very ugly and so I want something that will just evaluate all of these and return me a value. I don't enough experience with writing methods which take in multiple inputs and also multiple inputs that vary so I would appreciate any help on this.
You can use all and a comprehension over the variable arguments (*args) of the funtion:
>>> def f(x):
... if x == 1:
... return True
... elif x == 0:
... return False
...
>>> def g(f, *args):
... return all(f(x) for x in args)
...
>>> g(f, 1, 0, 0, 1)
False
>>> g(f, 1, 1, 1)
True
You can use the existing all function that is equivalent to a logical AND:
def f(x):
return x < 5
all((f(1), f(2), f(3), f(4)))
Now concerning function g you can do this (for example):
def g(f, inputs):
for i in inputs:
yield f(i)
all(g(f, range(5)))
Here you can replace range(5) with any of [0, 1, 2, 3, 4], (0, 1, 2, 3, 4), {0, 1, 2, 3, 4}, and many more (ie. any iterable).
Note that a function similar to g also exists in python, it's called map, you could use it this way:
all(map(f, range(5))) # More or less equivalent to all(g(f, range(5)))
You could also directly make use a generator expression (an alternative to the yield generator form):
all(f(i) for i in range(5))
Which one of this solution is the best really depend on the use case and on your personal preferences (even if the last one is probably the one you will most commonly see).
For AND function, you can use python's all, and for OR function, you can use python's any
>>> all([True, False])
False
>>> all([True, True])
True
>>> any([True, False])
True
>>> any([True, True])
True
>>> any([False, False])
False
Just append all your outputs in a list, and evaluate all or any, so considering function f you defined
print(all([f(1),f(1)]))
print(all([f(0),f(0)]))
print(any([f(1), f(0)]))
print(any([f(0), f(0)]))
#True
#False
#True
#False

python use multiple values in multiple function

How to do something like this in python
def func1():
x = 2
y = 3
return x, y
def funcx():
print(func1().x)
def funcy():
print(func1().y)
So basically return multiple values from a single function then use each returned value in a different function
Python functions can return only one value, but it is easy for that value to contain others. In your example, func1 returns a single tuple, which in turn contains two values.
>>> def func1():
... x = 2
... y = 3
... return x, y
...
>>> func1()
(2, 3)
You can index or unpack this return value just like any other tuple:
>>> func1()[0]
2
>>> func1()[1]
3
>>> a, b = func1()
>>> a
2
You can use indexing also in your desired functions:
def funcx():
print(func1()[0])
def funcy():
print(func1()[1])
If you desire named fields, you can use a dict or namedtuple:
# dict
def func1():
return {'x': 2, 'y': 3}
def funcx():
print(func1()['x'])
# namedtuple
from collections import namedtuple
Point2D = namedtuple('Point2D', ['x', 'y'])
def func1():
return Point2D(x=2, y=3)
def funcx():
print(func1().x)

How to test if an input has only specific characters

Im trying to make a script that tests id there are characters in the input that are not A, T, C, G and if there are than the input is false.
I dont have any clue how to start. I would love if someone could help.
Thanks!
The following function can check a string to find out if it only contains the characters A, T, C, and G.
def check_string(code):
return all(character in {'A', 'T', 'C', 'G'} for character in code)
Expressed using sets:
The list function takes a string and returns a list of its characters. The set function takes a list and returns a set (with duplicates discarded).
>>> def check_string(code):
... return set(list('ACTG')).issuperset(set(list(code)))
...
>>> check_string('IT')
False
>>> check_string('ACTG')
True
>>> check_string('')
True
>>> check_string('ACT')
True
output = True
nucl_dict = {'A':'T', 'T':'A', 'C':'G', 'G':'C'}
n = input("Insert DNA seqence: ").upper()
for c in n:
if(c in ("A", "T", "C", "G")):
output = False
if(output == False):
print('Issue detected please try again')
print(n)
print(''.join(nucl_dict.get(nucl, nucl) for nucl in n))
else:
print("All good")

Which character comes first?

So the input is word and I want to know if a or b comes first.
I can use a_index = word.find('a') and compare this to b_index = word.find('b') and if a is first, a is first is returned. But if b isn't in word, .find() will return -1, so simply comparing b_index < a_index would return b is first. This could be accomplished by adding more if-statements, but is there a cleaner way?
function description:
input: word, [list of characters]
output: the character in the list that appears first in the word
Example: first_instance("butterfly", ['a', 'u', 'e'] returns u
You can create a function that takes word and a list of chars - convert those chars into a set for fast lookup and looping over word take the first letter found, eg:
# Chars can be any iterable whose elements are characters
def first_of(word, chars):
# Remove duplicates and get O(1) lookup time
lookup = set(chars)
# Use optional default argument to next to return `None` if no matches found
return next((ch for ch in word if ch in lookup), None)
Example:
>>> first_of('bob', 'a')
>>> first_of('bob', 'b')
'b'
>>> first_of('abob', 'ab')
'a'
>>> first_of("butterfly", ['a', 'u', 'e'])
'u'
This way you're only ever iterating over word once and short-circuit on the first letter found instead of running multiple finds, storing the results and then computing the lowest index.
Make a list without the missing chars and then sort it by positions.
def first_found(word, chars):
places = [x for x in ((word.find(c), c) for c in chars) if x[0] != -1]
if not places:
# no char was found
return None
else:
return min(places)[1]
In any case you need to check the type of the input:
if isinstance(your_input, str):
a_index = your_input.find('a')
b_index = your_input.find('b')
# Compare the a and b indexes
elif isinstance(your_input, list):
a_index = your_input.index('a')
b_index = your_input.index('b')
# Compare the a and b indexes
else:
# Do something else
EDIT:
def first_instance(word, lst):
indexes = {}
for c in lst:
if c not in indexes:
indexes[c] = word.find(c)
else:
pass
return min(indexes, key=indexes.get)
It will return the character from list lst which comes first in the word.
If you need to return the index of this letter then replace the return statement with this:
return min_value = indexes[min(indexes, key=indexes.get)]

Resources