I have two lists
a = [1,2,3]
b = [2,3,4,5]
and two custom functions F1(a[i]) and F2(b[j]), which take elements from lists a and b return objects, say A and B. And there is a custom comparison function diff(A,B), which returns False if the objects are the same in some sense and True if they are different.
I would like to compare these two lists in a pythonic way to see if the lists are the same. In other words, that all objects A generated from list a have at least one equal object B generated from list b. For example if the outcome is the following then the lists are the same:
(diff(F1(1),F2(4)) or diff(F1(1),F2(5)) or diff(F1(2),F2(3)) or diff(F1(3),F2(2))) is False
For the function sorted there is a key function. Are there any comparison functions in Python that can take a custom function in this situation?
The only solution that I see is to loop through all elements in a and loop through all elements in b to check them element by element. But then if I want to extend the functionality this would require quite some development. If there is a way to use standard Python functions this would be very much appreciated.
all(True if any(diff(A, B) is False for B in [F2(j) for j in b]) else False for A in [F1(i) for i in a])
Honestly I just typed this quickly using my Python auto-pilot but it would look something like this I guess.
Probably the best you can get is first converting all entries of the list, and then iterate over both and check if any of a has a match in b and if that holds true for all as. So something like
af = [F1(i) for i in a]
bf = [F2(i) for i in b]
is_equal = all(any(not diff(a,b) for b in bf) for a in af )
all stops as soon as it finds the first value that is false, any stops as soon as it finds the first value that is True.
Related
When I use the an in b statement with string, it works well. However, when my objects change to the type of list, it returns false even though the first list is in the second list. What's the logic behind this?
def f(a,b):
if a in b:
return True
else:
return False
f('soifsdf','sh')
True
f([1, 2], [1, 2, 3])
False
I change another method not in method, but it still doesn't work.
Objects can define in (via __contains__) as they choose. list only defines it for single elements. The are a number of reasons for this. One is consistency. Another is that it avoids multiple layers of ambiguity. For example, what if b contains an element equal to a? You also need to decide clearly whether you want subsequences, ordered subsets, or regular subsets including count or not.
I have a list A of about 62,000 numbers, and another list B of about 370,000. I would like to filter B so that it contains only elements from A. I tried something like this:
A=[0,3,5,73,88,43,2,1]
B=[0,5,10,42,43,56,83,88,892,1089,3165]
C=[item for item in A if item in set(B)]
Which works, but is obviously very slow for such large lists because (I think?) the search continues through the entire B, even when the element has already been found in B. So the script is going through a list of 370,000 elements 62,000 times.
The elements in A and B are unique (B contains a list of unique values between 0 and 700,000 and A contains a unique subset of those) so once A[i] is found in B, the search can stop. The values are also in ascending order, if that means anything.
Is there some way to do this more quickly?
This is creating a new set(B) for every item in A. Instead, use the built-in set.intersection:
C = set(A).intersection(B)
To be really sure what I've done is the fastest possible, I would have done that :
A=[0,3,5,73,88,43,2,1]
B=[0,5,10,42,43,56,83,88,892,1089,3165]
B_filter = B.copy()
C = []
for item in A:
if filter in B_filter:
C.append(item)
B_filter.pop(0) # B_filter is a list, and it's in ascending order so always the first
If you don't care about losing your B list, you can just use B instead of B_filter and not declare B_filter, so you don't have to copy a 370k large list.
I have a list of elements to sort and a comparison function cmp(x,y) which decides if x should appear before y or after y. The catch is that some elements do not have a defined order. The cmp function returns "don't care".
Example: Input: [A,B,C,D], and C > D, B > D. Output: many correct answers, e.g. [D,C,B,A] or [A,D,B,C]. All I need is one output from all possible outputs..
I was not able to use the Python's sort for this and my solution is the old-fashioned bubble-sort to start with an empty list and insert one element at a time to the right place to keep the list sorted all the time.
Is it possible to use the built-in sort/sorted function for this purpose? What would be the key?
It's not possible to use the built-in sort for this. Instead, you need to implement a Topological Sort.
The built-in sort method requires that cmp imposes a total ordering. It doesn't work if the comparisons are inconsistent. If it returns that A < B one time it must always return that, and it must return that B > A if the arguments are reversed.
You can make your cmp implementation work if you introduce an arbitrary tiebreaker. If two elements don't have a defined order, make one up. You could return cmp(id(a), id(b)) for instance -- compare the objects by their arbitrary ID numbers.
Suppose I have a list A, which I want to grow depending on some values in list B. I want to append B to A, and in the case B is empty, I want to input a predefined value to indicate this.
if B:
A.extend(B)
else:
A.append('no value')
This code does exactly what I want, but my only problem is that it doesn't look very pythonic. I'm pretty sure there must be a way to do this in one line where the if-else statement is in the list comprehension, something like:
A.extend([[x for x in B] if B else 'no value'])
This line almost works, but it in the case A = [] and B = [1], I end up with A = [[1]], which does not work for what I want to do.
Any ideas how to make this work?
Pass a list with the default value; there is no need for a list comprehension here either:
A.extend(B or ['no value'])
I used or here because an empty list is considered false in a boolean context; it is more compact here and avoids repeating yourself.
The conditional expression version would be:
A.extend(B if B else ['no value'])
I'm trying to see if a set in python contains the elements of another set. I've tried to use set comparison but the problem is I need to be able to recognise only an exact match of elements. For example a subset of [3,3] will match a set of [3,1,2] when I want it to only match to [3,3,1], or any set variant with two threes.
I am iterating through all possible variants of a 3 element set using numbers 0-4, trying to see which ones contain the [3,3] set. Should I be using sets or is it better to use a list? Any ideas on how to do this?
Cheers
sets cannot contain duplicate elements. you can use a list or a dict where the value for the key is the number of times the key occurs in your set.
Something like:
d1 = {3:2, 1:1}
d2 = {3:2}
all(d1.get(k,0)-v>=0 for (k,v) in d2.items())
Assuming that by set you mean list, something like this should work (not tested):
def contains(superset, subset):
for elem in set(superset):
if superset.count(elem) < subset.count(elem):
return False
return True
If you want to have duplicates in your sets (making them really multisets or "bags", rather than proper sets), you should use collections.Counter. It supports set operations (&, +, -) with appropriate multiset semantics.
Testing if one multiset a is a subset of another multiset b can be done with a == a & b:
from collections import Counter
a = Counter([3,3])
b = Counter([3,1,2])
print(a == a & b) # prints False, since a is not a subset of b