I am working on a backtracking solution for this problem - "Given a string s, partition s such that every substring of the partition is a palindrome."
I have written this code where I am not able to get how is the global 2D list strings is getting updated? What exactly is happening here? I tried using global keyword too with it inside palinBreak function, but it doesn't help! When should global keyword be used?
Observation: Every element of global list strings changes to local list variable arr. For instance, strings = [x, y] and arr = [z], then strings becomes [z, z, z]; whereas I want it to be [x, y, z]. Why does this happen?
EDIT: Adding expected output vs. output I am getting (take notice from line 3 onwards).
Expected output is:
ans is ['a', 'b', 'a', 'a', 'b'] []
strings is [['a', 'b', 'a', 'a', 'b']]
ans is ['a', 'b', 'aa', 'b'] [['a', 'b', 'a', 'a', 'b']]
strings is [['a', 'b', 'a', 'a', 'b'], ['a', 'b', 'aa', 'b']]
ans is ['a', 'baab'] [['a', 'b', 'a', 'a', 'b'], ['a', 'b', 'aa', 'b']]
strings is [['a', 'b', 'a', 'a', 'b'], ['a', 'b', 'aa', 'b'], ['a', 'baab']]
ans is ['aba', 'a', 'b'] [['a', 'b', 'a', 'a', 'b'], ['a', 'b', 'aa', 'b'], ['a', 'baab']]
strings is [['a', 'b', 'a', 'a', 'b'], ['a', 'b', 'aa', 'b'], ['a', 'baab'], ['aba', 'a', 'b']]
[['a', 'b', 'a', 'a', 'b'], ['a', 'b', 'aa', 'b'], ['a', 'baab'], ['aba', 'a', 'b']]
Output:
ans is ['a', 'b', 'a', 'a', 'b'] []
strings is [['a', 'b', 'a', 'a', 'b']]
ans is ['a', 'b', 'aa', 'b'] [['a', 'b', 'aa', 'b']]
strings is [['a', 'b', 'aa', 'b'], ['a', 'b', 'aa', 'b']]
ans is ['a', 'baab'] [['a', 'baab'], ['a', 'baab']]
strings is [['a', 'baab'], ['a', 'baab'], ['a', 'baab']]
ans is ['aba', 'a', 'b'] [['aba', 'a', 'b'], ['aba', 'a', 'b'], ['aba', 'a', 'b']]
strings is [['aba', 'a', 'b'], ['aba', 'a', 'b'], ['aba', 'a', 'b'], ['aba', 'a', 'b']]
[[], [], [], []]
>>>
Code:
def isPalin(s):
i = 0
j = len(s)-1
while(i<j):
if(s[i]!=s[j]):
return False
i+=1
j-=1
return True
def palinBreak(s, start, arr):
#print "Called", start, arr
#global strings
if(start==len(s)):
print "ans is", arr, strings
strings.append(arr)
print "strings is", strings
return 0
flag = -1
for i in range(1, len(s)-start+1):
curr = s[start : start+i]
#print "Testing curr and start and i", curr, start, i
if(isPalin(curr)):
arr.append(curr)
#print arr, start, i
#print "Next call from", start+i
pb = palinBreak(s, start+i, arr)
if(pb != -1):
flag = 1
arr.pop()
#print "popped l", arr
return flag
strings = []
palinBreak("abaab", 0, [])
print strings
The problem is that arr will be the same list in the inner recursive calls.
Try to replace
pb = palinBreak(s, start+i, arr)
with
pb = palinBreak(s, start+i, list(arr))
Related
I have a list like the following:
lst = ['a', 'a', 'a', 'start', 'b', 'end', 'a', 'a','a','start','b','b','b','end','a','a','a','a','start','b','b','end']
and my desired result is to split the list into sublists like this:
[['a', 'a', 'a'], ['start', 'b', 'end'], ['a', 'a','a'],['start','b','b','b','end'],['a','a','a','a'],['start','b','b','end']]
so start and end are keywords, is there anyway you can use .split() by using particular keywords/if it matches?
So far I have made a function which finds the indices of 'start' i.e. starting_ind = [3, 9, 18] and ending_ind = [5, 13, 21] however if I do
temp=[]
for i in range(len(starting_ind)):
x = lst[starting_ind[i]: ending_ind[i]]
temp += x
print(temp)
the result is incorrect.
This solution doesn't require you to calculate indices beforehand:
lst = ['a', 'a', 'a', 'start', 'b', 'end', 'a', 'a', 'a', 'start', 'b', 'b',
'b', 'end', 'a', 'a', 'a', 'a', 'start', 'b', 'b', 'end', 'a', 'a', 'a']
result = []
sublist = []
for el in range(len(lst)):
if lst[el] == 'start':
result.append(sublist.copy())
sublist.clear()
sublist.append(lst[el])
else:
sublist.append(lst[el])
if lst[el] == 'end':
result.append(sublist.copy())
sublist.clear()
if el == len(lst) - 1:
result.append(sublist)
print(result)
The result is:
[['a', 'a', 'a'], ['start', 'b', 'end'], ['a', 'a', 'a'], ['start', 'b', 'b', 'b', 'end'], ['a', 'a', 'a', 'a'], ['start', 'b', 'b', 'end'], ['a', 'a', 'a']]
Here's a possible way to use regular expression to extract the patterns, please check if it's acceptable:
import re
lst = ['a','a','a', 'start','b','end', 'a','a','a', 'start','b','b','b','end', 'a','a','a','a', 'start','b','b','end']
result = []
for e in re.findall('a_[a_]+|start[_b]+_end', '_'.join(lst)):
result.append(e.strip('_').split('_'))
print(result)
Output is as desired:
[['a', 'a', 'a'],
['start', 'b', 'end'],
['a', 'a', 'a'],
['start', 'b', 'b', 'b', 'end'],
['a', 'a', 'a', 'a'],
['start', 'b', 'b', 'end']]
A better way is this:
result = []
for e in re.split(r'(start[_b]+_end)', '_'.join(lst)):
result.append(e.strip('_').split('_'))
print([x for x in result if x != ['']])
Same output
You can write so:
lst = ['a', 'a', 'a', 'start', 'b', 'end',
'a', 'a','a','start','b','b','b','end','a','a','a','a','start','b','b','end']
temp=[]
ind = [0, 3, 6, 9, 14, 18, 22]
for i in range(len(ind)-1):
x = lst[ind[i]: ind[i+1]]
temp.append(x)
print(temp)
and you will get:
[['a', 'a', 'a'], ['start', 'b', 'end'], ['a', 'a', 'a'], ['start', 'b', 'b', 'b', 'end'], ['a', 'a', 'a', 'a'], ['start', 'b', 'b', 'end']]
If you can be certain that your keywords will always appear in pairs, and in the right order (i.e. there will never be a 'start' without an 'end' that follows it, at some point in the list), this should work:
l = ['a', 'a', 'a', 'start', 'b', 'end', 'a', 'a','a','start','b','b','b','end','a','a','a','a','start','b','b','end']
def get_sublist(l):
try:
return l[:l.index('end') + 1] if l.index('start') == 0 else l[:l.index('start')]
except ValueError:
return l
result = []
while l:
sublist = get_sublist(l)
result.append(sublist)
l = l[len(sublist):]
print(result)
Gives the following result:
[['a', 'a', 'a'],
['start', 'b', 'end'],
['a', 'a', 'a'],
['start', 'b', 'b', 'b', 'end'],
['a', 'a', 'a', 'a'],
['start', 'b', 'b', 'end']]
For example the original list:
['k','a','b','c','a','d','e','a','b','e','f','j','a','c','a','b']
We want to split the list into lists started with 'a' and ended with 'a', like the following:
['a','b','c','a']
['a','d','e','a']
['a','b','e','f','j','a']
['a','c','a']
The final ouput can also be a list of lists. I have tried a double for loop approach with 'a' as the condition, but this is inefficient and not pythonic.
One possible solution is using re (regex)
import re
l = ['k','a','b','c','a','d','e','a','b','e','f','j','a','c','a','b']
r = [list(f"a{_}a") for _ in re.findall("(?<=a)[^a]+(?=a)", "".join(l))]
print(r)
# [['a', 'b', 'c', 'a'], ['a', 'd', 'e', 'a'], ['a', 'b', 'e', 'f', 'j', 'a'], ['a', 'c', 'a']]
You can do this in one loop:
lst = ['k','a','b','c','a','d','e','a','b','e','f','j','a','c','a','b']
out = [[]]
for i in lst:
if i == 'a':
out[-1].append(i)
out.append([])
out[-1].append(i)
out = out[1:] if out[-1][-1] == 'a' else out[1:-1]
Also using numpy.split:
out = [ary.tolist() + ['a'] for ary in np.split(lst, np.where(np.array(lst) == 'a')[0])[1:-1]]
Output:
[['a', 'b', 'c', 'a'], ['a', 'd', 'e', 'a'], ['a', 'b', 'e', 'f', 'j', 'a'], ['a', 'c', 'a']]
Firstly you can store the indices of 'a' from the list.
oList = ['k','a','b','c','a','d','e','a','b','e','f','j','a','c','a','b']
idx_a = list()
for idx, char in enumerate(oList):
if char == 'a':
idx_a.append(idx)
Then for every consecutive indices you can get the sub-list and store it in a list
ans = [oList[idx_a[x]:idx_a[x + 1] + 1] for x in range(len(idx_a))]
You can also get more such lists if you take in-between indices also.
You can do this with a single iteration and a simple state machine:
original_list = list('kabcadeabefjacab')
multiple_lists = []
for c in original_list:
if multiple_lists:
multiple_lists[-1].append(c)
if c == 'a':
multiple_lists.append([c])
if multiple_lists[-1][-1] != 'a':
multiple_lists.pop()
print(multiple_lists)
[['a', 'b', 'c', 'a'], ['a', 'd', 'e', 'a'], ['a', 'b', 'e', 'f', 'j', 'a'], ['a', 'c', 'a']]
We can use str.split() to split the list once we str.join() it to a string, and then use a f-string to add back the stripped "a"s. Note that even if the list starts/ends with an "a", this the split list will have an empty string representing the substring before the split, so our unpacking logic that discards the first + last subsequences will still work as intended.
def split(data):
_, *subseqs, _ = "".join(data).split("a")
return [list(f"a{seq}a") for seq in subseqs]
Output:
>>> from pprint import pprint
>>> testdata = ['k','a','b','c','a','d','e','a','b','e','f','j','a','c','a','b']
>>> pprint(split(testdata))
[['a', 'b', 'c', 'a'],
['a', 'd', 'e', 'a'],
['a', 'b', 'e', 'f', 'j', 'a'],
['a', 'c', 'a']]
This question already has answers here:
How do I use itertools.groupby()?
(15 answers)
Closed last month.
This is my list:
nab = ['b', 'b', 'a', 'b', 'b', 'b', 'a', 'a', 'a', 'a']
I want to combine the same elements which are adjacent into another list, and if they are not the same, just return the element itself.
The output that I am looking for is:
['b', 'a', 'b', 'a']
I mean:
two 'b' ---> 'b', one 'a' ---> 'a', three 'b' ---> 'b', four 'a' ---> 'a'
I want to know the length of the new list.
Thank you so much #tdelaney, I did it as below:
import itertools
nab = ['B', 'B', 'A', 'B', 'B', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'A', 'A', 'B', 'B', 'A', 'A', 'B', 'A', 'B', 'B', 'B', 'B', 'A']
U = []
key_func = lambda x: x[0]
for key, group in itertools.groupby(nab, key_func):
U.append(list(group))
print(U)
print(len(U))
Output:
[['B', 'B'], ['A'], ['B', 'B'], ['A', 'A', 'A', 'A'], ['B', 'B', 'B'], ['A', 'A'], ['B', 'B'], ['A', 'A'], ['B'], ['A'], ['B', 'B', 'B', 'B'], ['A']]
The issues stems from the output.append(a) on the third line. This program would ideally output 6 unique permutations of the input string, but instead returns 6 of the first result in the recursive loop. I realize exiting the recursion may have something to do with the array being modified, but how can I circumvent this issue to be able to return an array of solutions?
def permute(a, l, r, output):
if l==r:
output.append(a)
else:
for i in range(l,r+1):
a[l], a[i] = a[i], a[l]
permute(a, l+1, r,output)
a[l], a[i] = a[i], a[l] # backtrack
Driver program to test the above function
string = "ABC"
output = []
n = len(string)
a = list(string)
permute(a, 0, n-1,output)
print(output)
For reference, this is what the output looks like:
[['A', 'C', 'B']]
[['B', 'A', 'C'], ['B', 'A', 'C']]
[['B', 'C', 'A'], ['B', 'C', 'A'], ['B', 'C', 'A']]
[['C', 'B', 'A'], ['C', 'B', 'A'], ['C', 'B', 'A'], ['C', 'B', 'A']]
[['C', 'A', 'B'], ['C', 'A', 'B'], ['C', 'A', 'B'], ['C', 'A', 'B'], ['C', 'A', 'B']]
[['A', 'B', 'C'], ['A', 'B', 'C'], ['A', 'B', 'C'], ['A', 'B', 'C'], ['A', 'B', 'C'], ['A', 'B', 'C']]
When the output should be:
['A', 'B', 'C']
['A', 'C', 'B']
['B', 'A', 'C']
['B', 'C', 'A']
['C', 'B', 'A']
['C', 'A', 'B']
The problem is in the line
output.append(a)
it looks fine, but later on the list a changes, and when you append it to output again, the previous a (that you already appended) changes.
To solve the problem, you can simply use shallow copy. Write this instead:
output.append(a[:])
Do you know there is an excisting function in python?
import itertools
listA = ["A", "B", "C"]
perm = itertools.permutations(listA)
for i in list(perm):
print(i)
Result:
('A', 'B', 'C')
('A', 'C', 'B')
('B', 'A', 'C')
('B', 'C', 'A')
('C', 'A', 'B')
('C', 'B', 'A')
I have a Nested List like this:
l = [['A', ['A', 'B', ['A', 'B', 'C'], ['A', 'B', 'D']], ['A', 'D', ['A', 'D', 'A']], ['A', 'C', ['A', 'C', 'B'], ['A', 'C', 'A']], ['A', 'A', ['A', 'A', 'D']]]]
I want to separate it to a List of all individual lists like this:
k = [['A'], ['A', 'B'], ['A', 'B', 'C'], ['A', 'B', 'D'], ['A', 'D'], ['A', 'D', 'A'], ['A', 'C'], ['A', 'C', 'B'], ['A', 'C', 'A'], ['A', 'A'], ['A', 'A', 'D']]
I tried this by creating the following function:
def un_nest(l):
k=[]
for item in l:
if type(item) is list:
un_nest(item)
else:
k+=[item]
print(k)
I got the required output, but I don't know how to convert it to list.
the output I got is:
['A', 'B', 'C']
['A', 'B', 'D']
['A', 'B']
['A', 'D', 'A']
['A', 'D']
['A', 'C', 'B']
['A', 'C', 'A']
['A', 'C']
['A', 'A', 'D']
['A', 'A']
['A']
[]
this was output in the shell, (I know this is because of print function), but i have no idea how to get the list from this. As I need to do some operation the the required list for final output.
I am using Python 3.4.1
Any hint will help. Thanks in advance
Edit:
Its more like I want to, separate all the strings and sub-list from 'l', to another list.
You could return a list as the result at the current nesting level and join together the nested results using extend.
l = [['A', ['A', 'B', ['A', 'B', 'C'], ['A', 'B', 'D']], ['A', 'D', ['A', 'D', 'A']], ['A', 'C', ['A', 'C', 'B'], ['A', 'C', 'A']], ['A', 'A', ['A', 'A', 'D']]]]
def un_nest(l):
r = []
k = []
for item in l:
if type(item) is list:
r.extend(un_nest(item))
else:
k.append(item)
if k:
r.insert(0, k)
return r
print(un_nest(l))
outputs:
[['A'], ['A', 'B'], ['A', 'B', 'C'], ['A', 'B', 'D'], ['A', 'D'], ['A', 'D', 'A'], ['A', 'C'], ['A', 'C', 'B'], ['A', 'C', 'A'], ['A', 'A'], ['A', 'A', 'D']]