Checking if elements exist in list using python - python

I am new to python and was wondering if someone could help me out with this. I am trying to see if the elements in b are in a. This is my attempt. Currently I am not getting any output. Any help would be appreciated, thank you!
a = [1]
b = [1,2,3,4,5,6,7]
for each in b:
if each not in a == True:
print(each + "is not in a")

You are testing two different things, and the outcome is False; Python is chaining the operators, effectively testing if (each is in a) and (a == True):
>>> 'a' in ['a'] == True
False
>>> ('a' in ['a']) and (['a'] == True)
False
>>> ('a' in ['a']) == True
True
You never need to test for True on an if statement anyway:
if each not in a:
is enough.

You should be able to just say:
if each not in a:
print ("%d is not in a" % each)
Your actual expression is using operator chaining:
if a > b > c:
parses as:
if (a > b) and (b > c):
in python. which means your expression is actually being parsed as:
if (each not in a) and (a == True):
but a == True will always return False, so that if block will never execute.

a = [1,2,3]
b = [1,2,3,4,5,6,7]
c = [7,8,9]
print set(a) <= set(b) #all elements of a are in b
print set(c) <= set(b) #all elements of c are in b

It is better to see the difference between B and A
set(b).difference(set(a))

You don't need ==True. Just:
if each not in a:

This is really easy using sets:
a = [1]
b = [1, 2]
only_in_b = set(b) - set(a)
# set([2])

Another way:
for bb in b:
try:
a.index(bb)
except:
print 'value is not in the list: ' + str(bb)

I would like to add that if the two lists are large. This is not the best way to do it. Your algorithm is O(n^2). The best way is to traverse a, adding the elements as keys to a dictionary. Afterwards, traverse the second list, checking if the elements are already in the dictionary, this instead is an O(n) algorithm.

Related

Python List with if Condition

I have two lists and I want to use both in if condition together.
In case only One list this can do easily
like if list_name : # if list a :
for more than 2 lists this method is not working.
although we can use separately if or using len(a) like comparison.
I am searching for simple & beautiful result.
a = [1,2,34]
b= [4,5,6,3]
# if a & b : # i was expecting this will work <br>
#if (a is True) & (b == True): # this all not working <br>
# if (len(a) >=1) & (len(b) >=1): # This will work but not beautiful <br>
#
print("Not Working") #
print("working ")
In Python, instead of using & in if statements, we use and.
This is how you can check both lists in the same if:
a = [1, 2, 3, 4]
b = [5, 6, 7, 8]
if a and b:
print("a and b are both valid!")
You can read more about Python if statements here.
Inside if-statements, lists are automatically evaluated as True or False, depending on whether they are empty or not. Therefore, we can simply write:
a = [1,2,34]
b = [4,5,6,3]
if a and b:
print('Hello World')
If you want to check if any list is non-empty, you can write a or b alternatively.
More information about the evaluation of if-statements:
What is Truthy and Falsy? How is it different from True and False?
Python has a very fancy way, working with lists.
Here are some very basic ones:
a = [1, 2, 3, 4]
b = [4, 5, 6, 7]
if a and b:
# Checks if there is something inside both lists
# returns True if there is at least 1 value inside every list
print("A and B not empty")
if a or b:
# Checks if there is something at least in one list
# returns True if there is at least 1 value inside of one list
print("Something in A or B")
if a[0] == b[0]:
# Checks the first value of both lists
print("Value 1 of A and B are equal")
# Loops through the list of a / you can use i as index
for i in range(len(a)):
if a[i] == b[i]:
print(f"{a[i]} is equal to {b[i]}")
# Alternative loop
for item in a:
print(item)

Why do these shorthands not work with each other?

I was wondering how to take advantage of shorthand notation of if-else and += in Python of this simple expression:
I tried to set brackets everywhere and changed += to *= which didn't change the situation of course.
This works as expected:
a, b = 0, True
for i in range(123):
if b == True:
a = a + 1
Still working as expected, trying shorthand of if-else led me to:
a, b = 0, True
for i in range(123):
a = a + 1 if b == True else a
Finally the attempt to write:
a, b = 0, True
for i in range(123):
a += 1 if b == True else a:
fails and surprisingly I get pretty quickly huge integers for a
Moreover I'd really like something more shorthanded, e.g.:
a, b = 0, True
for i in range(123):
a += 1 if b
The for-loop needs to stay as it is, since in my case there are other operations that affect b.
Since noone seems to be posting, why it goes like this, here is mine - lines:
a = a + 1 if b == True else a
a += 1 if b == True else a
are seen by python as:
a = (a + 1 if b == True else a)
a += (1 if b == True else a)
This is why you get large numbers fast in second version - you will add a to a, when b is False. If you want to keep the if, then go:
a += (1 if b else 0)
Also don't compare b to True (or False), go foif b`, as it's more pythonic (it will prevent some weird mistakes, when other code will start to interact with yours).
EDIT: go for #Tomerikoo answer for even shorter code, but keep in mind, that those waters can be muddy and not everyone knows / easily follows, that adding boolean to int treats first as 1 (or 0 if False).
To closest to your proal is probably:
a, b = 0, True
for i in range(123):
a += b
Since bool is a subtype of int, no conversion is necessary.
You can do:
for i in range(123):
if b:a+=1
You can also do:
for i in range(123):
a = a + 1*b
Because booleans are ints:
>>> isinstance(True, int)
True
>>> True == 1
True
just note that
a += x if condition else y
will resolve to a += x if the condition is True; otherwise it will be a += y. this is why your numbers get big...
apart from that i suggest you use what U10-Forward's answer suggests.

Comparing all items of one list present in another and in same order

In the following code, how do I return only those values as True, where order of elements in checklist is followed in routelist?
For eg:
checklist(["BOMH","DELH","BRGH"]) should return as True ["BOMH","CCUH","DELH","BRGH"] but not ["BOMH","BRGH","CCUH","DELH"].
def checklhcost2(checklist):
thcdataselect["shortlist"] = thcdataselect.apply(lambda x:\
True if all((i in x["routelist"] for i in checklist)) else False)
return thcdataselect.filter_by(1,"shortlist")
Use a mapping to determine the weight of each value, filter out the ones that don't match, and check that it's ordered properly:
master = ["BOMH","DELH","BRGH"]
ordering = {item:idx for idx,item in enumerate(master)}
check1 = ["BOMH","CCUH","DELH","BRGH"]
check2 = ["BOMH","BRGH","CCUH","DELH"]
def check(o, c):
return all(o[i]==r for i,r in zip((i for i in c if i in o), range(len(o))))
Result:
>>> check(ordering, check1)
True
>>> check(ordering, check2)
False
>>> chk = ["BOMH","DELH","BRGH"]
>>> one = ["BOMH","CCUH","DELH","BRGH"]
>>> two = ["BOMH","BRGH","CCUH","DELH"]
Make a set for membership testing
>>> set_chk = set(chk)
Generator expressions to filter AND maintain order
>>> one_a = (thing for thing in one if thing in set_chk)
>>> two_a = (thing for thing in two if thing in set_chk)
Use zip to pair up items in chk and the target lists for comparison.
>>> all(a == b for a, b in zip(chk, one_a))
True
>>> all(a == b for a, b in zip(chk, two_a))
False
To ensure all items are present as well as in the correct order, use itertools.zip_longest.
>>> three = ['BOMH', 'CCUH', 'DELH']
>>> three_a = (thing for thing in three if thing in set_chk)
>>>
>>> from itertools import zip_longest
>>>
>>> all(a == b for a,b in zip_longest(chk, three_a))
False
>>>
Using zip would have produced an incorrect result:
>>> all(a == b for a,b in zip(chk, three_a))
True
Or just make new, filtered lists and compare.
>>> one_a = [thing for thing in one if thing in set_chk]
>>> two_a = [thing for thing in two if thing in set_chk]
>>> three_a = [thing for thing in three if thing in set_chk]
>>> one_a == chk
True
>>> two_a == chk
False
>>> three_a == chk
False
def checklhcost2(values):
expected_seq = ["BOMH","DELH","BRGH"]
# for each element in expected_seq get index from values
L = [values.index(v) if v in values else -1 for v in expected_seq]
# if indexes are in increasing order and >1 then return True
return all(x<y and x > -1 for x, y in zip(L, L[1:]))
checklhcost2(["BOMH","CCUH","DELH","BRGH"])
#True
checklhcost2(["BOMH","BRGH","CCUH","DELH"])
#False
It also works on edge cases where expected_seq has values which the input parameter doesn't example
expected_seq = ["BOMH","DELH","BRGH", "other"]
checklhcost2(["BOMH","CCUH","DELH","BRGH"])
#False
checklhcost2(["BOMH","BRGH","CCUH","DELH"])
#False
Not sure this is a good solution, but it seems it works.
>>> checklhcost2 = lambda chl: reduce(lambda x,y: x and routelist.index(y[1]) == y[0], enumerate([ itm for itm in chl if itm in routelist]), True )
>>> checklhcost2(["BOMH","CCUH","DELH","BRGH"])
True
>>> checklhcost2(["BOMH","BRGH","CCUH","DELH"])
False
>>>
The main idea is quite simple: filter out everything which is not in routelist, then enumerate the rest and check indexes. Return logical and of match for all indexes (reduce function).

Most efficient way of checking list membership of more that one value

Take the following code:
a = [1,2,3,4]
if 1 in a or 2 in a:
print 'found'
Is there a cleaner/more elegant way of doing this? Perhaps:
a = [1,2,3,4]
b = [1,2]
if set(a) & set(b):
print found
Your second example based on set doesn't work because it will always return True for non-empty a/b. However sets are likely the right to use:
if set(b).issubset(set(a)):
print "found"
Please note that b = set([]) is always a subset of set(a).
Update: I just noticed that you only want to know if any of the items in b is part of a which is different from my proposed solution. In that case I think a simple if/elif/else is the best solution. You could try to use a dict or another iterable with fast contains-lookup.
a = [1,2,3,4]
b = [1,2]
print any(x in a for x in b)
True
Maybe this is too simple, but if...elif seems fine to me:
found = False
if 1 in a:
found = True
elif 2 in a:
found = True
This only checks if 2 is in the list if 1 isn't, since you're only looking to see if either is in the list (not caring which one), this should be good
Pros:
Its simple
You can save a check on 2 if 1 is already in the list
No need to convert a to a different type (which aides efficiency)
Cons:
This won't get you any points for flair
Timing Comparison:
basecase = """
a = [1,2,3,4]
if 1 in a or 2 in a:
print 'found'
"""
case1 = """
a = [1,2,3,4]
b = [1,2]
if set(b).issubset(set(a)):
print 'found'
"""
case2 = """
found = False
if 1 in a:
found = True
elif 2 in a:
found = True
"""
case3 = """
a = [1,2,3,4]
b = [1,2]
print any(x in a for x in b)
"""
Using print min(timeit.Timer(<case>).repeat(8, 1000)) yields
basecase = 0.0953138421204
case1 = 0.0974782045301
case2 = 0.0958207179797
case3 = 0.068283250742
You can try
if set(a) <= set(b):
print found
But I can't tell if it's more efficient than your code.

Checking if two lists share at least one element [duplicate]

This question already has answers here:
Test if lists share any items in python
(9 answers)
Closed 4 years ago.
I have two lists, for example:
a = ["mail1", "mail2", "mail3", "mail4"]
b = ["mail2", "mail5"]
and I want to check if any of the elements in list b also appears in list a.
I wanted to know if there is a way (and what is it) to do this without a for loop.
Also I wanted to know how can I create a list of boolean values, where each value will be the result of the comparison of values a[i] and b[i], something like:
[z for i, j in zip(a, b) z = i == j] # (just with the right syntax)
z will be 1 if in some place i == j, so I can check the array for any 'True' values.
You can use any:
any(x in a for x in b)
The nice thing about this generator expression is that any will return True as soon as the generator yields a True, i.e. there won't be redundant x in a lookups.
Edit:
You can improve the time complexity by making a set from a.
a_set = set(a)
any(x in a_set for x in b)
Regarding your new question:
[x == y for x,y in zip(a,b)]
Elegant way is to use sets:
a = ["mail1", "mail2", "mail3", "mail4"]
b = ["mail2", "mail5"]
anb = set(a) & set(b)
print anb
if anb:
print True
>>> set(['mail2'])
>>> True
The any function takes in an iterable (See documentation here), so the answer should be any([x in a for x in b])

Categories

Resources