As per title, given n sets like the following:
set1 = {"aa","ab","ba","cc","ca"},
set2 = {"fr","fa","po","pl","cc"},
set3 = {"fr","xz","hn","fa"},
set4 = {"jq","we","hn","ca","aa","fk"},
set5 = {"jp","wx","we","fr","ba"}
I want to get the exclusively intersections between them, conceptually like a Venn Diagram representation. So, for example:
The intersection between the set2 and set3, despite sharing {"fr","fa"}, will only be {"fa"}, as the string "fr" is also present in the intersection between set2,set3 and set5.
The brilliant solution proposed in this answer managed correctly all the permutations of given sets, but didn't manage to account for exclusivity, considering each overlap independently. So, in the previous example, it'll return {"fr","fa"}
Tryout
I tried to handle this situation in a very slow way, and want to know if there's a more proficient way to do the job.
By creating a list of sets
set_list = [set1, set2, set3, set4, set5]
I start from finding the whole sets intersection
whole_intersect = set.intersections(*map(set,set_list))
Then I'm moving in every permutation of length n-1 using list indices
isect_1_2_3_4 = set.intersections(*map(set, map(set_list.__getitem__, [0,1,2,3])) - whole_intersect
isect_1_2_3_5 = set.intersections(*map(set, map(set_list.__getitem__, [0,1,2,5])) - whole_intersect
..
Then by n-2
isect_1_2_3 = set.intersections(*map(set, map(set_list.__getitem__, [0,1,2])) - whole_intersect - isect_1_2_3_4 - isect_1_2_3_5
..
Till filling intersections of 2 sets
isect_1_2 = set.intersections(*map(set, map(set_list.__getitem__, [0,1,2])) - whole_intersect - isect_1_2_3_4 - isect_1_2_3_5 - isect_1_2_3 - isect_1_2_4 - isect_1_2_5
..
As expectable, this approach is a true pain. How could I manage to do it in a less handcrafted and pythonic way?
I think I have done it by first making a dictionary of all of the intersections, of every combination, and then finding the unique intersection by taking the intersection and subtracting the union of every other intersection:
import itertools
set1 = {"aa","ab","ba","cc","ca"}
set2 = {"fr","fa","po","pl","cc"}
set3 = {"fr","xz","hn","fa"}
set4 = {"jq","we","hn","ca","aa","fk"}
set5 = {"jp","wx","we","fr","ba"}
sets = {
1: set1,
2: set2,
3: set3,
4: set4,
5: set5
}
intersections = {}
for n_combinations in range(2, len(sets) + 1):
tmp = list(map(dict, itertools.combinations(sets.items(), n_combinations)))
tmp = {tuple(x.keys()):set.intersection(*list(x.values())) for x in tmp}
intersections.update(tmp)
unique_in_intersection = {}
for n_combinations in range(2, len(sets)+1):
for lookup_set in itertools.combinations(range(1, len(sets)+1), n_combinations):
s1_intersection_s2 = intersections[lookup_set]
union_other_intersections = set.union(*[v for k, v in intersections.items() if k != lookup_set and len(k) > len(lookup_set)])
unique_in_intersection[lookup_set] = s1_intersection_s2 - union_other_intersections
result:
{
(1, 2): {'cc'},
(1, 3): set(),
(1, 4): {'ca', 'aa'},
(1, 5): {'ba'},
(2, 3): {'fa'},
(2, 4): set(),
(2, 5): set(),
(3, 4): {'hn'},
(3, 5): set(),
(4, 5): {'we'},
(1, 2, 3): set(),
(1, 2, 4): set(),
(1, 2, 5): set(),
(1, 3, 4): set(),
(1, 3, 5): set(),
(1, 4, 5): set(),
(2, 3, 4): set(),
(2, 3, 5): {'fr'},
(2, 4, 5): set(),
(3, 4, 5): set(),
(1, 2, 3, 4): set(),
(1, 2, 3, 5): set(),
(1, 2, 4, 5): set(),
(1, 3, 4, 5): set(),
(2, 3, 4, 5): set(),
(1, 2, 3, 4, 5): set()
}
Related
Context of the problem:
Find Pair with given Sum in the Array.
Given an unsorted list of ints, find a pair with a given sum in it.
EXAMPLE:
list = [8, 7, 2, 5, 3, 1]
sum = 10
OUTPUT = index 0 & 2 (8, 2) or 1 & 4 (7, 3)
This is what I have so far:
def find_pair_dict(ints: [int], sum_: int):
dict_ = dict()
# {
# element: index
# 8: 0,
# 7: 1,
# ...
# }
output = list()
for i in range(len(ints)):
diff = sum_ - ints[i]
# print(diff)
if diff not in dict_.keys():
# int: index
dict_[ints[i]] = i
else:
output.append((dict_[ints[i]], dict_[diff]))
if not output:
return "No pairs were found"
return output
I am calling this function with find_pair_dict([8, 7, 2, 5, 3, 1], 10) and am getting an error that I do not understand.
The Error
Traceback (most recent call last):
File "find_pair_sum.py", line 62, in <module>
print(find_pair_dict([8, 7, 2, 5, 3, 1], 10))
File "find_pair_sum.py", line 53, in find_pair_dict
output.append((dict_[ints[i]], dict_[diff]))
KeyError: 2
This sounds like the element of 2 cannot be added?
Almost a one-liner:
def find_pairs(ints: [int], sum_: int):
return {
tuple(sorted((n, ints.index(sum_-i)))): (i, sum_-i)
for n, i in enumerate(ints) if sum_ - i in ints
}
print(find_pairs([8, 7, 2, 5, 3, 1], 10))
Result:
{(0, 2): (2, 8), (1, 4): (3, 7), (3, 3): (5, 5)}
Note: the key to the dictionary is a sorted tuple. A tuple because a list isn't hashable and sorted to avoid both (0,2) and (2,0) showing up as keys (for example).
The error in your solution occurs because the first time this line is executed:
output.append((dict_[ints[i]], dict_[diff]))
The value if dict_ is {8: 0, 7: 1} and ints[i] is 2. Since there is no entry for 2 in the dict, you get this error.
Actually I think there should be three outputs:
(2,0) = 2,8
(4,1) = 3,7
(3,3) = 5,5
The problem has already been succinctly described by #Selcuk. I am suggesting you how to solve that. Many ways. Easiest for me is to use defaultdict from collections.
Below is the code with minimal changes
from collections import defaultdict
def find_pair_dict(ints: [int], sum_: int):
dict_ = defaultdict(list)
output = list()
for i in range(len(ints)):
diff = sum_ - ints[i]
dict_[ints[i]] = i
output.append((dict_[ints[i]], dict_[diff]))
if not output:
return "No pairs were found"
return output
print(find_pair_dict([8, 7, 2, 5, 3, 1], 10))
This prints out the following. I have not filtered for empty matches.
[(0, []), (1, []), (2, 0), (3, 3), (4, 1), (5, [])]
Is this what you wanted?
This question already has answers here:
How do I generate all permutations of a list?
(40 answers)
Closed 3 years ago.
trying to make a function permutations(s) that takes a set of elemnts and returns a collection of all its permutations, where the permutations are of type tuple.
Here is my code:
def permutations(s):
str1 = list(s)
if len(str1) <= 1:
print(s)
else:
for i in range(0, len(s)):
str1[0], str1[i] = str1[i], str1[0]
permutations(str1[1:])
str1[0], str1[i] = str1[i], str1[0]
given this input
print(sorted(permutations({1,2,3})))
it should return
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]
but after alot of headache i can only seem to get
[3][2][3][1][1][2]
You can use permutations from itertools in the standard library to compute all permutations
from itertools import permutations
out = list(permutations({1,2,3}))
print(out)
#Output
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]
You are probably looking for an algorithm, e.g. recursive algorithm. Some times ago I wrote it (as exercise):
def get_permutations(array):
result = list()
def permute(x, index, acc=[0] * len(array)):
if index == len(array):
result.append(acc[:])
acc = list()
return None
for j in range(len(x)):
acc[index] = x[j]
_x = x[:]
_x.pop(j)
permute(_x, index + 1, acc)
permute(array, 0)
return result
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I want to implement a function, generate_perm(m,n), where it takes two arguments, one is for numbers to permutate (m) and second is to what the sum of the permutation must equate to (n).
def generate_perm(m,n):
'''
implement this
'''
return
generate_perm(2,5) should output
[(1,4), (2,3), (3,2) (4,1)]
and
generate_perm(3,5) should output:
[(1,1,3), (1,2,2), (1,3,1), (2,1,2), (2,2,1), (3,1,1)]
EDIT
i havent gotten far
def generate_permutations(m, n):
all = []
cur = [0 for i in range(m)]
len_perm = m*2
while True:
for i in range(m):
if cur[i] == 0: # initial case
if i != m-1:
cur[i] = 1
else:
cur[i] = n-m
all.append(cur)
if len(all) >= len_perm:
break
return all
Consider a list l = [1,2,3,4,5]
You can get all the permutations with itertools.permutations
p = itertools.permutations(list(range(1,6)),2)
and then filter them
my_elems = [el for el in p if sum(el) == 5]
outputs
[(1, 4), (2, 3), (3, 2), (4, 1)]
Looking at the second example you give, I think what you want is a product, not permutations:
p = itertools.product(list(range(1,6)),repeat=3)
my_elems = [el for el in p if sum(el) == 5]
#[(1, 1, 3), (1, 2, 2), (1, 3, 1), (2, 1, 2), (2, 2, 1), (3, 1, 1)]
and which works also for the first case.
One simple recursive approach without any libraries:
def perm(m, n):
if m == 1: # base case
return [(n,)]
perms = []
for s in range(1, n): # combine possible start values: 1 through n-1 ...
for p in perm(m-1, n-s): # ... with all appropriate smaller perms
perms.append((s,) + p)
return perms
>>> perm(1, 5)
[(5,)]
>>> perm(2, 5)
[(1, 4), (2, 3), (3, 2), (4, 1)]
>>> perm(3, 5)
[(1, 1, 3), (1, 2, 2), (1, 3, 1), (2, 1, 2), (2, 2, 1), (3, 1, 1)]
I have been recently using Counter().most_common but the problem is that I need to turn the bit where it shows how much it came up into a percentage, for example:
[(2, 5), (10, 5)]
to:
[(2, 50%), (10, 50%)]
Is there any way of doing this using Counter().most_common, or any other method?
Here is part of my code:
while count < int(DR):
count = count + int(1)
DV.append(random.randint(1, int(DI)))
if count == int(DR):
print ('\n(The Number that was rolled , the amount of times it came up):')
global x
print (Counter(DV).most_common(int((DI))))
from collections import Counter
l = [1, 1, 2, 2, 2, 2, 2, 3, 4, 10, 10, 10, 10, 10]
c = Counter(l)
[(i, c[i] / len(l) * 100.0) for i in c]
Output, in the form (element, % of total)
[(1, 14.285714285714285),
(2, 35.714285714285715),
(3, 7.142857142857142),
(4, 7.142857142857142),
(10, 35.714285714285715)]
To list them in order you can use collections.Counter.most_common
>>> [(i, c[i] / len(l) * 100.0) for i, count in c.most_common()]
[(2, 35.714285714285715),
(10, 35.714285714285715),
(1, 14.285714285714285),
(3, 7.142857142857142),
(4, 7.142857142857142)]
If you don't have the original data, you can still accomplish this just with the Counter.
OrderedDict([(i, str(round(count / sum(c.values()) * 100.0, 3)) + '%') for i, count in c.most_common()])
Where:
i is the item that was counted;
count is the count of that item;
c is the Counter object
3 is the precision of the percentage
Performance can be improved if sum(c.values()) is moved outside of the list compression.
matrix
is a list of lists with the same length. I've to return a dictionary of the form
{i:(l1[i],l2[i],...,lm[i])}
Where the key i is matched with a tuple the i'th elements
from each list.
Say
matrix=[[1,2,3,4],[9,8,7,6],[4,8,2,6]]
so the line:
>>> dict([(i,tuple(matrix[k][i] for k in xrange(len(matrix)))) for i in xrange(len(matrix[0]))])
does the job pretty well and outputs:
{0: (1, 9, 4), 1: (2, 8, 8), 2: (3, 7, 2), 3: (4, 6, 6)}
but fails if the matrix is empty: matrix=[]. The output should be: {}
How can i deal with this?
How about this instead:
>>> matrix = [[1,2,3,4],[9,8,7,6],[4,8,2,6]]
>>> dict(enumerate(zip(*matrix)))
{0: (1, 5, 4), 3: (4, 8, 6), 2: (3, 7, 2), 1: (2, 6, 8)}
>>> matrix = []
>>> dict(enumerate(zip(*matrix)))
{}
try changing part "len(matrix[0])"
This will try look up an index that doesn't exist if the matrix is empty.
instead make it
len(matrix[0]) if matrix else 0
If you want a simple solution (instead of knowing what's wrong with your one), I suggest you use a list instead of a dict. Seeing as a matrix is fairly static in terms of its size and keys.
This can be done simply by zip(*matrix)
>>> matrix = [[1,2,3,4],[9,8,7,6],[4,8,2,6]]
>>> dict_ = dict(enumerate(zip(*matrix)))
>>> list_ = zip(*matrix)
>>> for key_ in dict_:
... print dict_[key_] == list_[key_]
...
True
True
True
True