(I'm sure this has been answered somewhere but I really couldn't find the right question. Perhaps I don't know the correct verb for this exercise?)
I have two lists:
prefix = ['A', 'B', 'C']
suffix = ['a', 'b']
And I want to get this:
output = ['A a', 'A b', 'B a', 'B b', 'C a', 'C b']
I am aware of the zip method, which stops at the shortest length among the lists joined:
output_wrong = [p+' '+s for p,s in zip(prefix,suffix)]
So what's the most Pythonic way of doing this?
EDIT:
While majority of the answers prefer itertools.product, I instead much prefer this:
output = [i + ' ' + j for i in prefix for j in suffix]
as it doesn't introduce a new package, however basic that package is (ok I don't know which way is faster and this might be a matter of personal preference).
Use List Comprehension
prefix = ['A', 'B', 'C']
suffix = ['a', 'b']
result = [val+" "+val2 for val in prefix for val2 in suffix ]
print(result)
OUTPUT
['A a', 'A b', 'B a', 'B b', 'C a', 'C b']
Using itertools.product and list comprehension,
>>> [i + ' ' + j for i, j in product(prefix, suffix)]
# ['A a', 'A b', 'B a', 'B b', 'C a', 'C b']
Use itertools.product:
import itertools
prefix = ['A', 'B', 'C']
suffix = ['a', 'b']
print([f'{x} {y}' for x, y in itertools.product(prefix, suffix)])
# ['A a', 'A b', 'B a', 'B b', 'C a', 'C b']
This is called a Cartesian product:
[p + ' ' + s for p, s in itertools.product(prefix, suffix)]
Use product,
In [33]: from itertools import product
In [34]: map(lambda x:' '.join(x),product(prefix,suffix))
Out[34]: ['A a', 'A b', 'B a', 'B b', 'C a', 'C b']
Simply use list comprehension:
prefix = ['A', 'B', 'C']
suffix = ['a', 'b']
output = [i+" "+j for i in prefix for j in suffix]
print(output)
Output:
['A a', 'A b', 'B a', 'B b', 'C a', 'C b']
from itertools import product
map(' '.join, product(prefix, suffix))
# ['A a', 'A b', 'B a', 'B b', 'C a', 'C b']
Related
I have a set of Strings: {'Type A', 'Type B', 'Type C'} for instance, I'll call it x. The set can have up to 10 strings.
There is also a big list of sets, for instance [{'Type A', 'Type B', 'Type C'}, {'Type A', 'Type B', 'Type C'}, {'Type B', 'Type C, 'Type D'}, {'Type E', 'Type F', 'Type G'}] and so on.
My goal is to return all the sets in the big list that contain 60% or more of the same elements as x. So in this example, it would return the first 3 sets but not the 4th.
I know I could iterate over every set, compare elements, and then use the number of similarities to go about my business, but this is quite time intensive and my big list will probably have many many sets. Is there a better way to go about this? I thought about using frozenset() and hashing them, but I'm not sure what hashing function I would use, and how I would compare hashes.
Any help would be appreciated - many thanks!
l = [{'Type A', 'Type B', 'Type C'}, {'Type A', 'Type B', 'Type C'}, {'Type B', 'Type C', 'Type D'}, {'Type E', 'Type F', 'Type G'}]
x = {'Type A', 'Type B', 'Type C'}
for s in l:
print (len(x.intersection(s)))
Output:
3
3
2
0
With a function and a list of tuples returned:
def more_than(l,n):
return [ (s,round(len(x.intersection(s))/len(x),2)) for s in l if len(x.intersection(s))/len(x) > n]
print (more_than(l,0.6))
Output:
[({'Type B', 'Type A', 'Type C'}, 1.0), ({'Type B', 'Type A', 'Type C'}, 1.0), ({'Type B', 'Type C', 'Type D'}, 0.67)]
Here, just for convenience, I used round(len(x.intersection(s))/len(x),2) which translates to round(x,y). The round() will simply round your ratio to the number of decimal mentioned using the y variable.
How about this?
x = {'Type A', 'Type B', 'Type C'}
lst = [{'Type A', 'Type B', 'Type C'},
{'Type A', 'Type B', 'Type C'},
{'Type B', 'Type C', 'Type D'},
{'Type E', 'Type F', 'Type G'}]
[s for s in lst if len(s.intersection(x)) > len(x) * 0.6]
Below is the use-case I am trying to solve:
I have 2 lists of lists: (l and d)
In [1197]: l
Out[1197]:
[['Cancer A', 'Ecog 9', 'Fill 6'],
['Cancer B', 'Ecog 1', 'Fill 1'],
['Cancer A', 'Ecog 0', 'Fill 0']]
In [1198]: d
Out[1198]: [[100], [200], [500]]
It's a 2-part problem here:
Sort l based on the priority of values. eg: Cancer, Ecog and Fill (in this case key=(0,1,2)). It could be anything like Ecog, Cancer, Fill so, key=(1,0,2).
Sort d in the same order in which l has been sorted int above step.
Step #1 I'm able to achieve, like below:
In [1199]: import operator
In [1200]: sorted_l = sorted(l, key=operator.itemgetter(0,1,2))
In [1201]: sorted_l
Out[1200]:
[['Cancer A', 'Ecog 0', 'Fill 0'],
['Cancer A', 'Ecog 9', 'Fill 6'],
['Cancer B', 'Ecog 1', 'Fill 1']]
Now, I want to sort values of d in the same order as the sorted_l.
Expected output:
In [1201]: d
Out[1201]: [[500], [100], [200]]
What is the best way to do this?
Below is the solution with help from #juanpa.arrivillaga :
In [1272]: import operator
In [1273]: key = operator.itemgetter(0, 1, 2)
# Here param key, lets you sort `l` with your own function.
In [1275]: sorted_l,sorted_d = zip(*sorted(zip(l, d), key=lambda x: key(x[0])))
In [1276]: sorted_l
Out[1276]:
(['Cancer A', 'Ecog 0', 'Fill 0'],
['Cancer A', 'Ecog 9', 'Fill 6'],
['Cancer B', 'Ecog 1', 'Fill 1'])
In [1277]: sorted_d
Out[1277]: ([500], [100], [200])
The code below generates unique combinations:
from itertools import permutations
comb3 = permutations([1,1,1,0,0,0] , 3)
def removeDuplicates(listofElements):
# Create an empty list to store unique elements
uniqueList = []
# Iterate over the original list and for each element
# add it to uniqueList, if its not already there.
for elem in listofElements:
elif elem not in uniqueList:
uniqueList.append(elem)
# Return the list of unique elements
return uniqueList
comb3 = removeDuplicates(comb3)
for i in list(comb3):
print(i)
Intermediate Output
The result output is a list of tuples. It will be interpreted as A, B, C, 1 = EXIST, 0 = NOT EXIST.
(1, 1, 1)
(1, 1, 0)
(1, 0, 1)
(1, 0, 0)
(0, 1, 1)
(0, 1, 0)
(0, 0, 1)
(0, 0, 0)
convert to list of lists
Convert lists of tuples to a list of lists and replace its contents
res = [list(ele) for ele in comb3]
for i in list(res):
if(i[0] == 1):
i[0] = 'A Exist'
if(i[0] == 0):
i[0] = 'A Not Exist'
if(i[1] == 1):
i[1] = 'B Exist'
if(i[1] == 0):
i[1] = 'B Not Exist'
if(i[2] == 1):
i[2] = 'C Exist'
if(i[2] == 0):
i[2] = 'C Not Exist'
Display results
for i in list(res):
print(i)
Final Output
['A Exist', 'B Exist', 'C Exist']
['A Exist', 'B Exist', 'C Not Exist']
['A Exist', 'B Not Exist', 'C Exist']
['A Exist', 'B Not Exist', 'C Not Exist']
['A Not Exist', 'B Exist', 'C Exist']
['A Not Exist', 'B Exist', 'C Not Exist']
['A Not Exist', 'B Not Exist', 'C Exist']
['A Not Exist', 'B Not Exist', 'C Not Exist']
Is there a more elegant or better way of replacing the contents of a list of list?
>>> names = ['A', 'B', 'C']
>>> verbs = [' Not Exist', ' Exist']
>>> [[names[n] + verbs[v] for n, v in enumerate(c)] for c in comb3]
[['A Exist', 'B Exist', 'C Exist'],
['A Exist', 'B Exist', 'C Not Exist'],
['A Exist', 'B Not Exist', 'C Exist'],
['A Exist', 'B Not Exist', 'C Not Exist'],
['A Not Exist', 'B Exist', 'C Exist'],
['A Not Exist', 'B Exist', 'C Not Exist'],
['A Not Exist', 'B Not Exist', 'C Exist'],
['A Not Exist', 'B Not Exist', 'C Not Exist']]]
First, it's inefficient to use permutations and then filter them out. What you're looking for is a cartesian product. Using itertools.product with a repeat argument, you can get your desired intermediate output.
from itertools import product
comb3 = list(product([1,0], repeat=3))
#Output:
[(1, 1, 1),
(1, 1, 0),
(1, 0, 1),
(1, 0, 0),
(0, 1, 1),
(0, 1, 0),
(0, 0, 1),
(0, 0, 0)]
From this point: You can use iteration and a mapping to cleanly get your desired output as follows.
column_names = 'ABC' #To map all names with the number of items. We can think of these as column names.
code_mapping = {0: 'Not Exist', 1: 'Exist'} #For mapping the codes to meanings.
output = []
for item in comb3:
row = [f"{name} {code_mapping[code]}" for name, code in zip(column_names, item)]
output.append(row)
print(output)
Output:
[['A Exist', 'B Exist', 'C Exist'],
['A Exist', 'B Exist', 'C Not Exist'],
['A Exist', 'B Not Exist', 'C Exist'],
['A Exist', 'B Not Exist', 'C Not Exist'],
['A Not Exist', 'B Exist', 'C Exist'],
['A Not Exist', 'B Exist', 'C Not Exist'],
['A Not Exist', 'B Not Exist', 'C Exist'],
['A Not Exist', 'B Not Exist', 'C Not Exist']]
You can use set to remove duplicates from a list.
Then map them to list
from itertools import permutations
import string
from pprint import pprint
alphabet = string.ascii_uppercase
comb3 = permutations([1,1,1,0,0,0] , 3)
comb3 = list(map(list,set(comb3)))
for i in comb3:
for index, value in enumerate(i):
i[index] = f'{alphabet[index]}{ " Not " if value>0 else " "}Exists'
pprint(comb3)
output
[['A Not Exists', 'B Not Exists', 'C Exists'],
['A Exists', 'B Not Exists', 'C Not Exists'],
['A Exists', 'B Not Exists', 'C Exists'],
['A Not Exists', 'B Exists', 'C Exists'],
['A Exists', 'B Exists', 'C Not Exists'],
['A Not Exists', 'B Exists', 'C Not Exists'],
['A Exists', 'B Exists', 'C Exists'],
['A Not Exists', 'B Not Exists', 'C Not Exists']]
You can do all of these just in 2 line:
comb3 = list(set(permutations([1,1,1,0,0,0] , 3))) # set will remove duplicates automatically
result = [[f"{i} {'' if j else 'NOT '}Exist" for i, j in zip(["A", "B", "C"], k)] for k in comb3]
result will be:
[['A Exist', 'B Exist', 'C NOT Exist'],
['A NOT Exist', 'B Exist', 'C Exist'],
['A NOT Exist', 'B Exist', 'C NOT Exist'],
['A Exist', 'B NOT Exist', 'C NOT Exist'],
['A NOT Exist', 'B NOT Exist', 'C Exist'],
['A Exist', 'B NOT Exist', 'C Exist'],
['A NOT Exist', 'B NOT Exist', 'C NOT Exist'],
['A Exist', 'B Exist', 'C Exist']]
Note that:
f'' works with python3.6 or higher.
You could do something like this:
a = ("A", "B", "C")
res = [["{} {}Exist".format(x, '' if y else 'NOT ') for x, y in zip(a, sub)] for sub in comb3]
or like that:
a = ("A {}Exist", "B {}Exist", "C {}Exist")
res = [[x.format('' if sub[i] else 'NOT ') for i, x in enumerate(a)] for sub in lst]
or the most elegant of 'em all:
a = [("A Not Exist", "B Not Exist", "C Not Exist"), ("A Exist", "B Exist", "C Exist")]
res = [[a[x][i] for i, x in enumerate(sub)] for sub in lst]
and they all return:
print(res) # -> [['A Exist', 'B Exist', 'C Exist'],
# ['A Exist', 'B Exist', 'C NOT Exist'],
# ['A Exist', 'B NOT Exist', 'C Exist'],
# ['A Exist', 'B NOT Exist', 'C NOT Exist'],
# ['A NOT Exist', 'B Exist', 'C Exist'],
# ['A NOT Exist', 'B Exist', 'C NOT Exist'],
# ['A NOT Exist', 'B NOT Exist', 'C Exist'],
# ['A NOT Exist', 'B NOT Exist', 'C NOT Exist']]
I have a tuple which consist of a number of teams that I have looped through and stored. The next step for me is to find the duplicates and store only one team, but update the number which indicate how many people are associated with the team.
_teamList = []
for obj in context['object_list']:
name = obj.team.name
number = 1
_teamList.append((name, number))
A example of a input looks something like:
[("Team bobcat", 1), ("Team Coffe", 1)]
here is the code for just getting the teams and add one to that.
I have tried something like this:
seen = set()
uniq = []
for x in _teamList:
if x not in seen:
x = 1 + x[1]
uniq.append(x)
seen.add(x)
Can anyone give me any tips?
You can refer this solution:
x=('team a', 'team b', 'team a', 'team c', 'team b', 'team b', 'team b')
l = {}
for i in x:
if i not in l:
l[i] = 1
else:
l[i] = l[i] + 1
data = list(tuple(l.items()))
print(data)
#output as: [('team a', 2), ('team b', 4), ('team c', 1)]
You can use 'Counter' from Collections.
https://docs.python.org/2/library/collections.html
This will automatically group the identical names for you. You need not calculate the number of occurrences.
For eg:
>>> from collections import Counter as c
>>> a = ('team a', 'team b', 'team a', 'team c', 'team b')
>>> c(a)
Counter({'team a': 2, 'team b': 2, 'team c': 1})
Here's a base Python solution:
a = ('team a', 'team b', 'team a', 'team c', 'team b', 'team b', 'team b')
d = {}
for x in a:
if x in d.keys():
d[x] += 1
else:
d[x] = 1
d
# {'team a': 2, 'team b': 4, 'team c': 1}
If you want the output as a tuple, add:
tuple((name, ct) for name, ct in d.items())
# (('team a', 2), ('team b', 4), ('team c', 1))
I've searched pretty thoroughly, and haven't found any info – hopefully I didn't miss anything. I have two lists:
list1 = (a, b, c, d)
list2 = (a, b*, c*, d)
I would like to generate all possible unique 2 list pairings that only look for differences at each index value. For example, the results here would be:
list1_new = (a, b*, c, d)
list2_new = (a, b, c*, d)
Note: I don't care to distinguish between list1 and list2, i.e., list1_new = (a, b*, c*, d) would not be considered unique as it matches the original list2.
I've played around with itertools but haven't been able to figure out how to compare at each index position.
I used small lists for this example, but I actually will have larger lists of 10+ items.
from itertools import product
list1 = ["a ", "b ", "c ", "d ", "e ", "f ", "g "]
list2 = ["a ", "b*", "c*", "d ", "e*", "f*", "g "]
# figure out which offsets have alternable values
crosses = [a != b for a,b in zip(list1, list2)]
offsets = [i for i,cross in enumerate(crosses) if cross]
# decide which offsets will be swapped
basis = [[0,1] for ofs in offsets]
basis[0] = [0] # only the first half - remainder are mirrors
swaps = product(*basis)
next(swaps, None) # skip base state == (list1, list2)
# print all viable swaps
list3 = list1[:]
list4 = list2[:]
for sw in swaps:
# build output lists
for which,offs in zip(sw, offsets):
list3[offs] = [list1, list2][which][offs]
list4[offs] = [list2, list1][which][offs]
# display output
print("\n{}\n{}".format(list3, list4))
gives
['a ', 'b ', 'c ', 'd ', 'e ', 'f*', 'g ']
['a ', 'b*', 'c*', 'd ', 'e*', 'f ', 'g ']
['a ', 'b ', 'c ', 'd ', 'e*', 'f ', 'g ']
['a ', 'b*', 'c*', 'd ', 'e ', 'f*', 'g ']
['a ', 'b ', 'c ', 'd ', 'e*', 'f*', 'g ']
['a ', 'b*', 'c*', 'd ', 'e ', 'f ', 'g ']
['a ', 'b ', 'c*', 'd ', 'e ', 'f ', 'g ']
['a ', 'b*', 'c ', 'd ', 'e*', 'f*', 'g ']
['a ', 'b ', 'c*', 'd ', 'e ', 'f*', 'g ']
['a ', 'b*', 'c ', 'd ', 'e*', 'f ', 'g ']
['a ', 'b ', 'c*', 'd ', 'e*', 'f ', 'g ']
['a ', 'b*', 'c ', 'd ', 'e ', 'f*', 'g ']
['a ', 'b ', 'c*', 'd ', 'e*', 'f*', 'g ']
['a ', 'b*', 'c ', 'd ', 'e ', 'f ', 'g ']