Weird list assignment - python

I'm trying to write program that will find all palindromes in a word. For example word "radar" has got 2 palindromes radar and ada. We skip single letters, so r, a, d, etc. aren't palindromes.
import copy
def ILEP(word):
lista = list(word)
counter = 0
pali = []
def isPalindrome(listaWord):
backup = copy.deepcopy(listaWord)
backup.reverse()
a = ''.join(backup)
b = ''.join(listaWord)
if(a == b):
return True
else:
return False
for i in range(len(lista)):
current = [lista[i]]
for j in range(i+1, len(lista)):
current.append(lista[j])
if(isPalindrome(current)):
print(current)
pali.append(current)
counter+=1
print(pali)
return counter
print(ILEP("radar"))
The program is finding all palindromes correctly, but it assings them wrong to the list pali. Console:
['r', 'a', 'd', 'a', 'r']
['a', 'd', 'a']
[['r', 'a', 'd', 'a', 'r'], ['a', 'd', 'a', 'r']]
2
As U can see it prints palindromes ['r', 'a', 'd', 'a', 'r'] and ['a', 'd', 'a'], but the list pali has got wrong value [['r', 'a', 'd', 'a', 'r'], ['a', 'd', 'a', 'r']]

You are changing your list current after appending to pali. You have to make a copy:
def is_palindrome(word):
return word[::-1] == word
def ILEP(word):
pali = []
for i, ch in enumerate(word):
current = [ch]
for ch in word[i+1:]:
current.append(ch)
if is_palindrome(current):
print(current)
pali.append(current[:])
print(pali)
return len(pali)
print(ILEP("radar"))

Related

Break a first for loop within a second for loop

I have almost completed a script to compare two lists (listA and listB).
The script should return the similar values between the lists, that are following each others, and with single occurrences.
listA=['b', 'c', 'd', 'c', 'c']
listB=['a', 'b', 'c']
def ordered_matches(list1, list2):
list = []
len1 = len(list1)
len2 = len(list2)
start_range = 0
for f1 in range(len1):
for f2 in range(start_range, len2):
if list1[f1] == list2[f2] and f2 != len2:
list.append(list1[f1]);
start_range = f2;
break
elif list1[f1] == list2[f2] and f2 == len2:
list.append(list1[f1]);
continue
break
return list
ordered_matches(listA, listB)
Here are examples of input/output expected:
listA=['a', 'b', 'c', 'd', 'e']
listB=['d', 'e', 'f', 'g', 'h']
output=['d','e']
listA=['a', 'b', 'c', 'd', 'e']
listB=['h', 'd', 'g', 'd', 'f']
output=['d']
listA=['b', 'a', 'c', 'a', 'e']
listB=['b', 'a', 'e', 'b', 'e']
output=['b', 'a', 'e']
To reach this result, the first for loop of the script should be broken.
But unfortunately, I can't manage to break the first for loop within the second for loop.
Would you have any advice to do it?
I think I have found an answer that does not require to break the outer loop. The main question of this topic is not addressed, but at least the script seems to work.
def ordered_matches(list1, list2):
list = []
len1 = len(list1)
len2 = len(list2)
start_range = 0
for f1 in range(len1):
for f2 in range(start_range, len2):
if list1[f1] == list2[f2]:
list.append(list1[f1]);
start_range = f2+1;
break
return list
However, it is noticeable that the position of the inputs in the command can change the outputs.

python consecutive elements to swap the list items [duplicate]

This question already has answers here:
What is the simplest way to swap each pair of adjoining chars in a string with Python?
(20 answers)
Closed 3 years ago.
here my input like:
['a','b','c','d','e','f']
output:
['b','a','d','c','f','e']
I tried to get consecutive list but i'm getting list in between empty string so please make to remove those empty list .
s = list(input().split())
def swap(c, i, j):
c[i], c[j] = c[j], c[i]
return ' '.join(c)
result = swap(s, 0, 1)
print(list(result))
current output:- ['b', ' ', 'a', ' ', 'c', ' ', 'd', ' ', 'e', ' ', 'f']
expected output:-['b', 'a', 'c', 'd', 'e','f']
You just need to return c as list, there is not need to convert to string and back again into a list:
s = ['a','b','c','d','e','f']
def swap(c, i, j):
c[i], c[j] = c[j], c[i]
return c
result = swap(s, 0, 1)
print(result)
Output:
['b', 'a', 'c', 'd', 'e', 'f']
a simple function to swap pairs that does not change the input:
def swap_pairs(list_to_swap):
s = list_to_swap[:] # create copy to not touch the original sequence
for i in range(0, len(s)-1, 2):
s[i], s[i+1] = s[i+1], s[i]
return s
s0 = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
s1 = ['a', 'b', 'c', 'd', 'e', 'f']
print(swap_pairs(s0))
print(swap_pairs(s1))
# ['b', 'a', 'd', 'c', 'f', 'e', 'g']
# ['b', 'a', 'd', 'c', 'f', 'e']
### check if s0 and s1 are untouched:
print(s0)
print(s1)
# ['a', 'b', 'c', 'd', 'e', 'f', 'g']
# ['a', 'b', 'c', 'd', 'e', 'f']
if you want to swap pairs 'in place', i.e. directly change the input, you could shorten the process to
def swap_pairs(s):
for i in range(0, len(s)-1, 2):
s[i], s[i+1] = s[i+1], s[i]
# return s
s1 = ['a', 'b', 'c', 'd', 'e', 'f']
swap_pairs(s1)
print(s1)
# ['b', 'a', 'd', 'c', 'f', 'e']
I think it's a matter of taste if a return statement should be added here. I'd consider it to be more clear not to return something since logically not needed. Anyway, be aware of variable scope.
this is the problem.. your joining on space. change it to the following.
def swap(c, i, j):
c[i], c[j] = c[j], c[i]
return ''.join(c)
for your output you could also do the following.
l = [x for x in [your output list] if x!= ' ']
or
l = [x for x in [your output list] if len(x.strip()) > 0]
Try returning only "C" and use recursion for swapping of all elements of list Then you will get expected Output. Check below code.
Output of below code: ['b','a','d','c','f','e']
s = ['a','b','c','d','e','f']
def swap(c, i, j):
if j<=len(c) and len(c)%2==0:
c[i], c[j] = c[j], c[i]
swap(c,i+2,j+2)
elif j<len(c):
c[i], c[j] = c[j], c[i]
swap(c,i+2,j+2)
return c
result = swap(s, 0, 1)
print(list(result))
and if you want Only output= ['b','a','c','d','e','f'] then no need of recursion just return c. Check below code:
s = ['a','b','c','d','e','f']
def swap(c, i, j):
c[i], c[j] = c[j], c[i]
return c
result = swap(s, 0, 1)
print(list(result))

replace duplicate values in a list with 'x'?

I am trying to understand the process of creating a function that can replace duplicate strings in a list of strings. for example, I want to convert this list
mylist = ['a', 'b', 'b', 'a', 'c', 'a']
to this
mylist = ['a', 'b', 'x', 'x', 'c', 'x']
initially, I know I need create my function and iterate through the list
def replace(foo):
newlist= []
for i in foo:
if foo[i] == foo[i+1]:
foo[i].replace('x')
return foo
However, I know there are two problems with this. the first is that I get an error stating
list indices must be integers or slices, not str
so I believe I should instead be operating on the range of this list, but I'm not sure how to implement it. The other being that this would only help me if the duplicate letter comes directly after my iteration (i).
Unfortunately, that's as far as my understanding of the problem reaches. If anyone can provide some clarification on this procedure for me, I would be very grateful.
Go through the list, and keep track of what you've seen in a set. Replace things you've seen before in the list with 'x':
mylist = ['a', 'b', 'b', 'a', 'c', 'a']
seen = set()
for i, e in enumerate(mylist):
if e in seen:
mylist[i] = 'x'
else:
seen.add(e)
print(mylist)
# ['a', 'b', 'x', 'x', 'c', 'x']
Simple Solution.
my_list = ['a', 'b', 'b', 'a', 'c', 'a']
new_list = []
for i in range(len(my_list)):
if my_list[i] in new_list:
new_list.append('x')
else:
new_list.append(my_list[i])
print(my_list)
print(new_list)
# output
#['a', 'b', 'b', 'a', 'c', 'a']
#['a', 'b', 'x', 'x', 'c', 'x']
The other solutions use indexing, which isn't necessarily required.
Really simply, you could check if the value is in the new list, else you can append x. If you wanted to use a function:
old = ['a', 'b', 'b', 'a', 'c']
def replace_dupes_with_x(l):
tmp = list()
for char in l:
if char in tmp:
tmp.append('x')
else:
tmp.append(char)
return tmp
new = replace_dupes_with_x(old)
You can use the following solution:
from collections import defaultdict
mylist = ['a', 'b', 'b', 'a', 'c', 'a']
ret, appear = [], defaultdict(int)
for c in mylist:
appear[c] += 1
ret.append(c if appear[c] == 1 else 'x')
Which will give you:
['a', 'b', 'x', 'x', 'c', 'x']

Rearrange strings in list alphabetically and by case

I have a list in a for loop and it uses itertools.product() to find different combinations of letters. I want to use collections.Counter() to count the number of occurrences of an item, however, right now it prints all the different combinations of "A"'s and "G"'s:
['a', 'A', 'G', 'G']
['a', 'A', 'G', 'g']
['a', 'A', 'G', 'G']
['a', 'A', 'G', 'g']
['a', 'A', 'G', 'g']
#...
['a', 'G', 'A', 'G']
['a', 'G', 'a', 'g']
['a', 'G', 'A', 'G']
['a', 'G', 'a', 'G']
['a', 'G', 'a', 'G']
#...
['a', 'G', 'a', 'G']
['a', 'G', 'A', 'G']
['a', 'G', 'a', 'g']
['a', 'G', 'A', 'G']
['a', 'G', 'a', 'G']
#...
['a', 'G', 'A', 'G']
['a', 'G', 'a', 'G']
['a', 'G', 'a', 'G']
# etc.
Now, this isn't all of them, but as you can see, there are some occurrences that are the same although ordered differently, for example:
['a', 'G', 'A', 'G']
['a', 'A', 'G', 'G']
I would much prefer the latter ordering, so I want to find a way to print all of the combinations with capital letters before lower case, and because 'a' is before 'g', also alphabetically. The final product should look like ['AaGG', 'aaGg', etc]. What function or functions should I use?
This is the code that generates the data. The section marked "Counting" is what I'm having trouble with.
import itertools
from collections import Counter
parent1 = 'aaGG'
parent2 = 'AaGg'
f1 = []
f1_ = []
genotypes = []
b = []
genetics = []
g = []
idx = []
parent1 = list(itertools.combinations(parent1, 2))
del parent1[0]
del parent1[4]
parent2 = list(itertools.combinations(parent2, 2))
del parent2[0]
del parent2[4]
for x in parent1:
f1.append(''.join(x))
for x in parent2:
f1_.append(''.join(x))
y = list(itertools.product(f1, f1_))
for x in y:
genotypes.append(''.join(x))
break
genotypes = [
thingies[0][0] + thingies[1][0] + thingies[0][1] + thingies[1][1]
for thingies in zip(parent1, parent2)
] * 4
print 'F1', Counter(genotypes)
# Counting
for genotype in genotypes:
alleles = list(itertools.combinations(genotype,2))
del alleles[1]
del alleles[3]
for x in alleles:
g.append(''.join(x))
for idx in g:
if idx.lower().count("a") == idx.lower().count("g") == 1:
break
f2 = list(itertools.product(g, g))
for x in f2:
genetics.append(''.join(x))
for genes in genetics:
if genes.lower().count("a") == genes.lower().count("g") == 2:
genes = ''.join(genes)
print Counter(genes)
I think you're looking for a customized way to define precedence; the lists are currently being ordered by ASCII numbering, which defines uppercase letters as always preceding lowercase letters. I would define customized precedence using a dictionary:
>>> test_list = ['a', 'A', 'g', 'G']
>>> precedence_dict = {'A':0, 'a':1, 'G':2,'g':3}
>>> test_list.sort(key=lambda x: precedence_dict[x])
>>> test_list
['A', 'a', 'G', 'g']
Edit:
Your last few lines:
for genes in genetics:
if genes.lower().count("a") == genes.lower().count("g") == 2:
genes = ''.join(genes)
print Counter(genes)
were not doing what you wanted them to.
Replace those lines with:
precedence_dict = {'A':0, 'a':1, 'G':2,'g':3}
for i in xrange(len(genetics)):
genetics[i] = list(genetics[i])
genetics[i].sort(key=lambda x: precedence_dict[x])
genetics[i] = ''.join(genetics[i])
from sets import Set
genetics = list(Set(genetics))
genetics.sort()
print genetics
and I think you have the correct solution. When iterating over elements in a for loop, Python makes a copy of the item. So the string 'genes' was actually not being modified in the original list.
I know you didn't ask for a code review, but you might be better off just generating the strings in the order you want in the first place instead of trying to filter them afterwards. Something like this might work.
def cross(parent1, parent2):
out = []
alleles = len(parent1)/2
# iterate parent 1 possible genotypes
for i in range(2):
# iterate loci
for k in range(alleles):
child = []
# iterate parent 2 possible genotypes
for j in range(2):
p1 = parent1[j * 2 + i]
p2 = parent2[j * 2 + k]
c = [p1, p2]
# get each genotype pair into capitalization order
c.sort()
c.reverse()
child += c
out.append("".join(child))
return out
if __name__ == "__main__":
parent1 = 'aaGG'
parent2 = 'AaGg'
# F1
f1 = cross(parent1, parent2)
print f1
# F2
f2 = []
for p1 in f1:
for p2 in f1:
f2 += cross(p1, p2)
print f2
Here's one way to get all combinations from a single parent. Start with the empty string and add the possibilities one by one.
def get_all_combos(allele_pair, gametes):
# Take a list of of genotypes. Return an updated list with each possibility from an allele pair
updated_gametes = []
for z in gametes:
updated_gametes.append(z + allele_pair[0])
updated_gametes.append(z + allele_pair[1])
return updated_gametes
if __name__ == "__main__":
parent1 = 'aaGG'
parent2 = 'AaGg'
alleles = len(parent2)/2
gametes = [""]
for a in range(alleles):
allele_pair = parent2[a*2:a*2+2]
gametes = get_all_combos(allele_pair, gametes)
print gametes
Maybe you can figure out how to combine these two solutions to get what you want.
you can try using the sort function.
Example of what I mean:
parent1 = "absdksakjcvjvugoh"
parent1sorted = list(parent1)
parent1sorted.sort()
print (parent1sorted)
The result you get is this : ['a', 'a', 'b', 'c', 'd', 'g', 'h', 'j', 'j', 'k', 'k', 'o', 's', 's', 'u', 'v', 'v']
Does this help you?
tldr:
Convert string into list, Sort list

How to create nested list from flatten list?

I wrote a function to create a nested list.
For example:
input= ['a','b','c','','d','e','f','g','','d','s','d','a','']
I want to create a sublist before ''
As a return I want a nested list like:
[['a','b','c'],['d','e','f','g'],['d','s','d','a']]
Try the following implementation
>>> def foo(inlist, delim = ''):
start = 0
try:
while True:
stop = inlist.index(delim, start)
yield inlist[start:stop]
start = stop + 1
except ValueError:
# if '' may not be the end delimiter
if start < len(inlist):
yield inlist[start:]
return
>>> list(foo(inlist))
[['a', 'b', 'c'], ['d', 'e', 'f', 'g'], ['d', 's', 'd', 'a']]
Another possible implementation could be by itertools.groupby. But then you have to filter the result to remove the ['']. But though it might look to be one-liner yet the above implementation is more pythonic as its intuitive and readable
>>> from itertools import ifilter, groupby
>>> list(ifilter(lambda e: '' not in e,
(list(v) for k,v in groupby(inlist, key = lambda e:e == ''))))
[['a', 'b', 'c'], ['d', 'e', 'f', 'g'], ['d', 's', 'd', 'a']]
I'd use itertools.groupby:
l = ['a','b','c','','d','e','f','g','','d','s','d','a','']
from itertools import groupby
[list(g) for k, g in groupby(l, bool) if k]
gives
[['a', 'b', 'c'], ['d', 'e', 'f', 'g'], ['d', 's', 'd', 'a']]
def nester(nput):
out = [[]]
for n in nput:
if n == '':
out.append([])
else:
out[-1].append(n)
if out[-1] == []:
out = out[:-1]
return out
edited to add check for empty list at end

Categories