I want to check in python 2.7 if a dictionary satisfies some restrictions I set. An satisfying example is: {1:[2], 2: [2,3], 3:False, 4: True}, however {1:[1, True]} is not ok. I want to forbid that keys map to True or False which are inside a list. Note, that I only want to detect if my restrictions are violated, I don't want to handle the case.
In the beginning I tested if a key maps to a list, and if it does I test if I have for some entry v: v == False or v == True, and if so I raise an ValueError. Then I learned that it does not work, because 1 == True is true.
Should I instead test v is False or v is True? Do you have suggestions on how to enforce the restrictions, or do you think my restrictions are bad practice?
Background: The dictionary maps state/label-tuples to successor states for an NFA, and I map to True and False to immediately accept/reject the word.
You can use isinstance:
In [16]: isinstance(True, bool)
Out[16]: True
In [17]: isinstance(1, bool)
Out[17]: False
You can use is as well:
In [18]: any(x is True or x is False for x in [True, 2])
Out[18]: True
An example one-line function with isinstance:
In [21]: is_good = lambda d: not any(any(isinstance(x, bool) for x in l)
....: for l in d.values() if isinstance(l, list))
In [22]: d = {1:[2], 2: [2,3], 3:False, 4: True}
In [23]: is_good(d)
Out[23]: True
In [24]: d[1][0] = False
In [25]: is_good(d)
Out[25]: False
A more explicit version of the same function:
def is_good(d):
for v in d.values():
if isinstance(v, list):
for x in v:
if isinstance(v, bool):
return False
return True
To respect duck-typing, if I did not want elements with a length to test true, I would test that, using len(), in addition to == True:
def issingle(v):
try:
len(v)
return False
except:
return True
x=[2,3]
y=1
issingle(x) ->> False
issingle(y) ->> True
Related
list1 = ['a','b','c','d']
list2 = ['b','c','d','a']
I have these two unordered lists and want to check if both have EXACTLY the same elements. Don't want to use set() or sorted() methods. But use looping to loop through both lists.
Keep it simple, without any helper function or list comprehension:
list1 = ['a','b','c','d']
list2 = ['b','c','d','a']
def same_lists(li1, li2):
if len(li1) != len(li2): # if the length of the lists is different than they are not equal so return false
return False
else:
for item1 in li1:
if item1 not in li2:
return False # if there is one item in li1 that is not in li2 than the lists are not identical so return false
for item2 in li2:
if item2 not in li1:
return False # same as three rows up
return True # if we didn't returned false for the whole list, than the lists are identical and we can return true.
print (same_lists(list1,list2))
This should work:
common_elements = [x for x in list1 if x in list2]
if len(list1) == len(list2) == len(common_elements):
print("EXACT SAME ELEMENTS")
else:
print("DIFFERENT ELEMENTS")
If you sort the elements first, or keep track as you encounter them, e.g. in another container, you can hand roll some solutions.
If you insist on avoiding this you need to check everything in the first list is in the seocnd and vice versa.
def same_lists(li1, li2):
if len(li1) != len(li2):
return False
else:
for item in li1:
if item not in li2:
return False
for item in li2:
if item not in li1:
return False
return True
This returns True for list1 = ['a','b','c','d'] compared with list2 = ['b','c','d','a'] and False for list3 = ['b','c','d','a', 'a'] and list4 = ['b','c','d','a', 'z'].
This is quadratic - we've compared everything with everything else (with a small optimisation checking the lengths first). We have to go through BOTH lists comaparing with the other list.
It would be quicker to sort first.
I have a list and I am trying to write a function returnMatchedElement(x:Int,y:Int,f:(Int,Int)=>Boolean) such that if a certain condition matches on an element of the list, it will return that element. Here's what I have got so far:
def returnMatchedElement(x:Int,l:List[Int],f:(Int,Int)=>Boolean):Int={
for (y<-l if f(x,y)) yield y
0}
def matchElements(a:Int,b:Int):Boolean= {if a==b true else false}
val l1=List(1,2,3,4,5)
returnMatchedElement(3,l1,matchElements)
res13: Int = 0
I am guessing I have a problem in understanding the yield keyword. What am I getting wrong here?
EDIT
The answer below works (thanks for that), but only if f returns boolean. I tried another example like this
def matchElements(a:Int,b:Int):Int= {if (a==b) 1 else 0}
def returnMatchedElement(x:Int,l:List[Int],f:(Int,Int)=>Int):Option[Int]={l.find(y => f(x, y))}
And now the compiler says
<console>:8: error: type mismatch;
found : Int
required: Boolean
def returnMatchedElement(x:Int,l:List[Int],f:(Int,Int)=>Int):Option[Int]={l.find(y => f(x, y))}
Simply use find, it finds the first element of the sequence satisfying a predicate, if any:
def returnMatchedElement(x: Int, l: List[Int], f: (Int,Int) => Boolean): Option[Int] = {
l.find(y => f(x, y))
}
I want a function that will compare, whether evaluated and non-evaluated expressions are different. So this:
import sympy.parsing.sympy_parser as spp
string = "x+x"
exp1 = spp.parse_expr(string, evaluate = False)
exp2 = spp.parse_expr(string)
print exp1
print exp2
print exp1 == exp2
Should output
x + x
2*x
False
And the same code with string = "x**2+1" should output
x**2+1
x**2+1
True # But it outputs False here too.
Yes, I have read the FAQ, but it doesn't explain how to fix/work around this.
The relevant issue is https://github.com/sympy/sympy/issues/5904.
When evaluate=False, the args property is not sorted:
>>> a = sympify('x**2 + 1', evaluate=False)
>>> b = sympify('x**2 + 1')
>>> a == b
False
>>> a.args
(x**2, 1)
>>> b.args
(1, x**2)
I don't believe (but you should check on the mailing list to be sure) that there is a built-in way to resolve this. The best approach depends on what you are trying to accomplish with this comparison.
The discussion at https://groups.google.com/forum/#!msg/sympy/LU5DQGJJhfc/_Le_u8UGtx0J (though outdated!) suggests making a custom comparison function, perhaps using the _sorted_args property:
>>> a._sorted_args
[1, x**2]
>>> b._sorted_args
[1, x**2]
I have a function that return [[]], and I want to test the result as unit test.
But I found that the expression [[]] == [[]] return false.
Here a simple test code:
# [[]] == [[]];;
- : bool = false
Can someone explain me why this expression is evaluated as false?
Thanks.
Use = since you have structural equality for comparing two values:
# [[]] = [[]];;
- : bool = true
Because == is reference equality, it only returns true if you refer to the same memory location:
let a = [[]]
let b = a
# b == a;;
- : bool = true
The == operator in OCaml means "physical equality". However, you have two (physically) different lists. Probably, you want "structural equality", which is tested by =.
I found, that there is related question, about how to find if at least one item exists in a list:
How to check if one of the following items is in a list?
But what is the best and pythonic way to find whether all items exists in a list?
Searching through the docs I found this solution:
>>> l = ['a', 'b', 'c']
>>> set(['a', 'b']) <= set(l)
True
>>> set(['a', 'x']) <= set(l)
False
Other solution would be this:
>>> l = ['a', 'b', 'c']
>>> all(x in l for x in ['a', 'b'])
True
>>> all(x in l for x in ['a', 'x'])
False
But here you must do more typing.
Is there any other solutions?
Operators like <= in Python are generally not overriden to mean something significantly different than "less than or equal to". It's unusual for the standard library does this--it smells like legacy API to me.
Use the equivalent and more clearly-named method, set.issubset. Note that you don't need to convert the argument to a set; it'll do that for you if needed.
set(['a', 'b']).issubset(['a', 'b', 'c'])
I would probably use set in the following manner :
set(l).issuperset(set(['a','b']))
or the other way round :
set(['a','b']).issubset(set(l))
I find it a bit more readable, but it may be over-kill. Sets are particularly useful to compute union/intersection/differences between collections, but it may not be the best option in this situation ...
I like these two because they seem the most logical, the latter being shorter and probably fastest (shown here using set literal syntax which has been backported to Python 2.7):
all(x in {'a', 'b', 'c'} for x in ['a', 'b'])
# or
{'a', 'b'}.issubset({'a', 'b', 'c'})
What if your lists contain duplicates like this:
v1 = ['s', 'h', 'e', 'e', 'p']
v2 = ['s', 's', 'h']
Sets do not contain duplicates. So, the following line returns True.
set(v2).issubset(v1)
To count for duplicates, you can use the code:
v1 = sorted(v1)
v2 = sorted(v2)
def is_subseq(v2, v1):
"""Check whether v2 is a subsequence of v1."""
it = iter(v1)
return all(c in it for c in v2)
So, the following line returns False.
is_subseq(v2, v1)
Not OP's case, but - for anyone who wants to assert intersection in dicts and ended up here due to poor googling (e.g. me) - you need to work with dict.items:
>>> a = {'key': 'value'}
>>> b = {'key': 'value', 'extra_key': 'extra_value'}
>>> all(item in a.items() for item in b.items())
True
>>> all(item in b.items() for item in a.items())
False
That's because dict.items returns tuples of key/value pairs, and much like any object in Python, they're interchangeably comparable
Another solution would be:
l = ['a', 'b', 'c']
potential_subset1 = ['a', 'b']
potential_subset2 = ['a', 'x']
print(False not in [i in l for i in potential_subset1]) # True
print(False not in [i in l for i in potential_subset2]) # False
What makes my solution great is that you can write one-liners by putting the lists inline.
An example of how to do this using a lambda expression would be:
issublist = lambda x, y: 0 in [_ in x for _ in y]
Short syntax
I discovered a very readable syntax while experimenting on the Python interpreter.
>>> my_list = [1, 2, 3, 4, 5]
>>> (6 or 7) in my_list
False
>>> (2 or 6) in my_list
True
>>> (2 and 6) in my_list
False
>>> (2 and 5) in my_list
True
List of items to search for
If you have a long list of objects to search for, held in a sub_list variable:
>>> my_list = [1, 2, 3, 4, 5]
>>> sub_list = ['x', 'y']
If any (at least one) item is contained in the superset (or statement):
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
False
>>> sub_list[0] = 3
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
True
If all items are contained in superset (and statement), then sub_list is a full subset. Also featuring a bit of De Morgan's Law:
>>> next((False for item in sub_list if item not in my_list), True)
False
>>> sub_list[1] = 2
>>> next((False for item in sub_list if item not in my_list), True)
True
>>> next((True for item in sub_list if next((True for x in my_list if x == item), False)), False)
True