I have the following requirement.
I have a list which say has 3 elements [X,Y,2]
What I would like to do is to generate strings with a separator (say "-") between (or not) each element. The order of the elements in the array should be preserved.
So the output would be:
'XY2'
'X-Y-2'
'X-Y2'
'XY-2'
is there an elegant way to this in python?
>>> import itertools
>>> for c in itertools.product(' -', repeat=2): print ('X%sY%s2' % c).replace(' ', '')
XY2
XY-2
X-Y2
X-Y-2
Or, with the elements coming from a python list:
import itertools
a = ['X', 'Y', 2]
for c in itertools.product(' -', repeat=2):
print ('%s%s%s%s%s' % (a[0],c[0],a[1],c[1],a[2])).replace(' ', '')
Or, in a slightly different style:
import itertools
a = ['X', 'Y', '2']
for c in itertools.product(' -', repeat=2):
print ( '%s'.join(a) % c ).replace(' ', '')
To capture the output to a list:
import itertools
a = ['X', 'Y', '2']
output = []
for c in itertools.product(' -', repeat=len(a)-1):
output.append( ('%s'.join(a) % c).replace(' ', '') )
print 'output=', output
A little more generalized but works for any number of separators and hopefully is easy to understand at each step:
import itertools
a = ['X', 'Y', '2']
all_separators = ['', '-', '+']
results = []
# this product puts all separators in all positions for len-1 (spaces between each element)
for this_separators in itertools.product(all_separators, repeat=len(a)-1):
this_result = []
for pair in itertools.izip_longest(a, this_separators, fillvalue=''):
for element in pair:
this_result.append(element)
# if you want it, here it is as a comprehension
# this_result = [element for pair
# in itertools.izip_longest(a, this_separators, fillvalue='')
# for element in pair]
this_result_string = ''.join(this_result) # check out join docs if it's new to you
results.append(this_result_string)
print results
>>> ['XY2', 'XY-2', 'XY+2', 'X-Y2', 'X-Y-2', 'X-Y+2', 'X+Y2', 'X+Y-2', 'X+Y+2']
These are the results for your case with just '' and '-' as separators:
>>> ['XY2', 'XY-2', 'X-Y2', 'X-Y-2']
If you want everything in one comprehension:
results = [''.join(element for pair
in itertools.izip_longest(a, this_separators, fillvalue='')
for element in pair)
for this_separators in itertools.product(all_separators, repeat=len(a)-1)]
I don't know if there is a function in itertool in order to do that. But i always think it's fun and a good exercice to do this kind of things. So there is a solution with recursive generator :
def generate(liste):
if len(liste) == 1:
yield [liste]
else:
for i in generate(liste[1:]):
yield [[liste[0]]]+i
yield [ [liste[0]]+i[0] ] + i[1:]
if __name__ == "__main__":
for i in generate (["X","Y","2"]):
print "test : " + str(i)
if len(i) == 1:
print "".join(i[0])
else:
print reduce(
lambda left, right : left + "".join(right),
i,
"")
Something like this?
from itertools import permutations
i = ["X","Y","2"]
for result in permutations(i, 3):
print "-".join(result)
Result:
X-Y-2
X-2-Y
Y-X-2
Y-2-X
2-X-Y
2-Y-X
Related
I'm a beginner who'd like to return strings in pairs of characters. If the input to the function is odd then the last pair it to include an _.
Example: solution("asdfadb") should return ['as', 'df', 'ad', 'b_']
My code however, returns: ['a', 's']['d', 'f']['a', 'd']['b', '_']
I've tried multiple ways and cannot get it to return the correctly formatted result:
def solution(s):
if len(s)%2 != 0:
s = "".join((s, "_"))
s = list(s)
s = [ s[i:i+2] for i in range(0 , len(s) , 2) ]
s = ''.join(str(pair) for pair in s )
print(s)
solution("asdfadb")
['a', 's']['d', 'f']['a', 'd']['b', '_']
You had a small confusion in the last list comprehension, try this (see my comment):
def solution(s):
if len(s)%2 != 0:
s = "".join((s, "_"))
s = list(s)
s = [ s[i:i+2] for i in range(0 , len(s) , 2) ]
s = [''.join(pair) for pair in s] # For each sublist (aka pair) - do join.
print(s)
Output:
['as', 'df', 'ad', 'b_']
Just a bit more compact than #idanz answer, but the principle is the same:
def solution(s: str):
s = s + "_" if len(s) % 2 !=0 else s
pairs = [s[i:i+2] for i in range(0, len(s), 2)]
print(pairs)
solution("asdfadb")
Output:
['as', 'df', 'ad', 'b_']
Here a solution using a list comprehension, string slicing, and zip_longest:
from itertools import zip_longest
def solution(string):
return ["".join(pair) for pair in zip_longest(string[0::2], string[1::2], fillvalue="_")]
print(solution("asdfadb"))
Output:
['as', 'df', 'ad', 'b_']
I have a list of strings, and want to use another list of strings and remove any instance of the combination of bad list in my list. Such as the output of the below would be foo, bar, foobar, foofoo... Currently I have tried a few things for example below
mylist = ['foo!', 'bar\\n', 'foobar!!??!!', 'foofoo::!*']
remove_list = ['\\n', '!', '*', '?', ':']
for remove in remove_list:
for strings in mylist:
strings = strings.replace(bad, ' ')
The above code doesnt work, I did at one point set it to a new variable and append that afterwords but that wasnt working well becuase if their was two issues in a string it would be appended twice.
You changed the temporary variable, not the original list. Instead, assign the result back into mylist
for bad in remove_list:
for pos, string in enumerate(mylist):
mylist[pos] = string.replace(bad, ' ')
Try this:
mylist = ['foo!', 'bar\\n', 'foobar!!??!!', 'foofoo::!*']
bads = ['\\n', '!', '*', '?', ':']
result = []
for s in mylist:
# s is a temporary copy
for bad in bads:
s = s.replace(bad, '') # for all bad remove it
result.append(s)
print(result)
Could be implemented more concise, but this way it's more understandable.
I had a hard time interpreting the question, but I see you have the result desired at the top of your question.
mylist = ['foo!', 'bar\\n', 'foobar!!??!!', 'foofoo::!*']
remove_list = ['\\n', '!', '*', '?', ':']
output = output[]
for strings in mylist:
for remove in remove_list:
strings = strings.replace(remove, '')
output.append(strings)
import re
for list1 in mylist:
t = regex.sub('', list1)
print(t)
If you just want to get rid of non-chars do this. It works a lot better than comparing two separate array lists.
Why not have regex do the work for you? No nested loops this way (just make sure to escape correctly):
import re
mylist = ['foo!', 'bar\\n', 'foobar!!??!!', 'foofoo::!*']
remove_list = [r'\\n', '\!', '\*', '\?', ':']
removals = re.compile('|'.join(remove_list))
print([removals.sub('', s) for s in mylist])
['foo', 'bar', 'foobar', 'foofoo']
Another solution you can use is a comprehension list and remove the characters you want. After that, you delete duplicates.
list_good = [word.replace(bad, '') for word in mylist for bad in remove_list]
list_good = list(set(list_good))
my_list = ["foo!", "bar\\n", "foobar!!??!!", "foofoo::*!"]
to_remove = ["!", "\\n", "?", ":", "*"]
for index, item in enumerate(my_list):
for char in to_remove:
if char in item:
item = item.replace(char, "")
my_list[index] = item
print(my_list) # outputs [“foo”,”bar”,”foobar”,”foofoo”]
I'm writing a function 'simplify' to simplify polynomials so that simplify("2xy-yx") can return "xy", simplify("-a+5ab+3a-c-2a")can return "-c+5ab" and so on.
I am at the stage where I have broken the polynomials into multiple monomials as elements for a list and have separated the coefficient of the monomials and the letter (variable) parts.
For instance
input = '3xy+y-2x+2xy'
My process gives me:
Var = ['xy', 'y', 'x', 'xy']
Coe = ['+3', '+1', '-2', '+2']
What I want to do is to merge the same monomials and add up their corresponding coefficients in the other list simultaneously.
My code was:
Play1 = Letter[:]
Play2 = Coe[:]
for i in range(len(Play1) - 1):
for j in range(i+1, len(Play1)):
if Play1[i] == Play1[j]:
Letter.pop(j)
Coe[i] = str(int(Play2[i]) + int(Play2[j]))
Coe.pop(j)
But this seems to only work with lists where each duplicate element appears no more than twice. For instance, input of "-a+5ab+3a-c-2a" gives me:
IndexError: pop index out of range
I thought of using set, but that will change the order.
What's the best way to proceed? Thanks.
Combine your lists with zip() for easier processing, and create a new list:
newVar = []
newCoe = []
for va, co in zip(Var, Coe):
# try/except (EAFP) is very Pythonic
try:
# See if this var is seen
ind = newVar.index(va)
# Yeah, seen, let's add the coefficient
newCoe[ind] = str(int(newCoe[ind]) + int(co))
except ValueError:
# No it's not seen, add both to the new lists
newVar.append(va)
newCoe.append(co)
Because all items are processed in their original order, as well as using list appending instead of hash tables (like set and dict), the order is preserved.
This is typically a use-case where dict come in handy :
from collections import defaultdict
Var = ['xy', 'y', 'x', 'xy']
Coe = ['+3', '+1', '-2', '+2']
polynom = defaultdict(int)
for var, coeff in zip(Var, Coe):
polynom[var] += int(coeff)
Var, Coe = list(polynom.keys()), list(polynom.values())
Your input was:
input = '3xy+y-2x+2xy'
You reached till:
Var = ['xy', 'y', 'x', 'xy']
Coe = ['+3', '+1', '-2', '+2']
Use below code to get --> +5xy-y-2x
def varCo(Var, Coe):
aa = {}
for k, i in enumerate(Var):
if i in aa: aa[i] += int(Coe[k])
else : aa[i] = "" if int(Coe[k]) == 1 else "-" if int(Coe[k]) == -1 else int(Coe[k])
aa = "".join([("" if "-" in str(v) else "+") + str(v)+i for i, v in aa.items() if v != 0])
return aa
Var = ['xy', 'y', 'x', 'xy']
Coe = ['+3', '-1', '-2', '+2']
print (varCo(Var, Coe))
#Result --> +5xy-y-2x
TRY THIS:
with using regex
import re
# a = '3xy+y-2x+2xy'
a = "-a+5ab+3a-c-2a"
i = re.findall(r"[\w]+", a)
j = re.findall(r"[\W]+", a)
if len(i)!=len(j):
j.insert(0,'+')
d = []
e = []
for k in i:
match = re.match(r"([0-9]+)([a-z]+)", k, re.I)
if match:
items = match.groups()
d.append(items[0])
e.append(items[1])
else:
d.append('1')
e.append(k)
print(e)
f = []
for ii,jj in zip(j,d):
f.append(ii+jj)
print(f)
Input:
a = "-a+5ab+3a-c-2a"
Output:
['a', 'ab', 'a', 'c', 'a']
['-1', '+5', '+3', '-1', '-2']
Input:
a = '3xy+y-2x+2xy'
Output:
['xy', 'y', 'x', 'xy']
['+3', '+1', '-2', '+2']
I have a Python string
string = aaa1bbb1ccc1ddd
and I want to split it like this
re.split('[split at all occurrences of "1", unless the 1 is followed by a c]', string)
so that the result is
['aaa', 'bbb1ccc', 'ddd']
How do I do this?
Use negative-lookahead with regex and the re module:
>>> string = 'aaa1bbb1ccc1ddd'
>>> import re
>>> re.split(r"1(?!c)", string)
['aaa', 'bbb1ccc', 'ddd']
def split_by_delim_except(s, delim, bar):
escape = '\b'
find = delim + bar
return map(lambda s: s.replace(escape, find),
s.replace(find, escape).split(delim))
split_by_delim_except('aaa1bbb1ccc1ddd', '1', 'c')
Although not as pretty as regex, my following code returns the same result:
string = 'aaa1bbb1ccc1ddd'
Split the string at all instances of '1'
p1 = string.split('1')
Create a new empty list so we can append our desired items to
new_result = []
count = 0
for j in p1:
if j.startswith('c'):
# This removes the previous element from the list and stores it in a variable.
prev_element = new_result.pop(count-1)
prev_one_plus_j = prev_element + '1' + j
new_result.append(prev_one_plus_j)
else:
new_result.append(j)
count += 1
print (new_result)
Output:
['aaa', 'bbb1ccc', 'ddd']
I'm trying to make a simple dict generator. It works but it isn't very functional yet.
I'd like to improve it by being able to change the max size of the output without touching the code.
letr='abcdefghijklmnopqrstuvwxyz'
for i in range(len(letr)):
t=letr[i]
print t
for t2 in letr:
print t+t2
for t3 in letr:
print t+t2+t3
for t4 in letr:
print t+t2+t3+t4
for t5 in letr:
print t+t2+t3+t4+t5
import itertools
def dict_gen(n):
letr = 'abcdefghijklmnopqrstuvwxyz'
return itertools.chain(''.join(j) for i in range(n)
for j in itertools.product(letr, repeat=i+1))
Usage:
for word in dict_gen(n): # replace n with the max word length you want
print word
Unlike some of the other answers this will include duplicates like your example ('aa', 'bb', etc).
dict_gen() will return a generator, but you can always just pass it into list() if you need to access elements by index:
>>> words = list(dict_gen(5))
>>> len(words) == 26 + 26**2 + 26**3 + 26**4 + 26**5 # verify correct length
True
>>> words[20:30] # transition from one letter to two letters
['u', 'v', 'w', 'x', 'y', 'z', 'aa', 'ab', 'ac', 'ad']
>>> words[-10:] # last 10 elements
['zzzzq', 'zzzzr', 'zzzzs', 'zzzzt', 'zzzzu', 'zzzzv', 'zzzzw', 'zzzzx', 'zzzzy', 'zzzzz']
letr = ''.join(chr(o) for o in range(ord('a'), ord('z') + 1))
import itertools
print [''.join(word) for word in itertools.permutations(letr, 5)]
Itertools is your best friend.
>>> import itertools
>>> gen = ("".join(i) for i in itertools.permutations(letr, 5))
>>> list(gen)[-10:]
['zyxwm', 'zyxwn', 'zyxwo', 'zyxwp', 'zyxwq', 'zyxwr', 'zyxws', 'zyxwt', 'zyxwu', 'zyxwv']
If you want to get all the permuations, you could write a generator yourself:
import itertools
def perms(seq):
for n in range(len(seq)+1):
for i in itertools.permutations(seq, n):
yield i
Check the Python documentation for itertools and generators for more info.