How can I convert this code into one liner or reduce the number of lines using list comprehension? - list-comprehension

def consecutive_zeros(input_binary):
count = 0
count_list = list()
for x in input_binary:
if x == "0":
count += 1
else:
count_list.append(count)
count = 0
return max(count_list)
I tried different ways to implement the same but was getting syntax error or wrong output.
Is there a more efficient way in which I can implement the same? How to make it one liner?

It looks like you want to find the longest sequence of zeros following a one. If this is correct zeros in the end should not be counted. I have a solution that is based on string operations as I assume your input is a string. If not please consider adding an example input to your question.
def consecutive_zeros(input_binary):
return max(map(len, input_binary.rstrip('0').split('1')))
print(consecutive_zeros('0000111110001000000')) # 4
print(consecutive_zeros('00001111100010000001')) # 6
EDIT: As your function is named consecutive_zeros it could be that you also want a sequence in the end, which would not be counted in your code. If you want to count it you can use this code:
def consecutive_zeros(input_binary):
return max(map(len, input_binary.split('1')))
print(consecutive_zeros('0000111110001000000')) # 6
print(consecutive_zeros('00001111100010000001')) # 6

Per the function in your question, which returns the number of leading 0s, you can use this:
def consecutive_zeros(input_binary):
return len(input_binary) - len(input_binary.lstrip('0'))

Related

Shortest code to return current index number in string in 'for n in 'word': loop

I have a question about strings. I thought that this code:
for n in 'banana':
print(n)
would return this:
0
1
2
3
4
5
But, of course, it doesn't. It returns the value at each position in the string, not the position number. In order for me to understand this better, I thought it might help to write the simplest possible program to achieve the output I thought I'd get:
count = 0
for n in 'banana':
print(count)
count += 1
This works, but surely there's a more direct way to access the position number that the current iteration is looking at? Can't see any methods that would achieve this directly though.
These are all equivalent:
i = 0
for n in 'banana':
print(i)
i += 1
for i, w in enumerate('banana'):
print(i)
for i in range(len('banana')):
print(i)
print(*range(len('banana')), sep='\n')
As posted in the other answer, enumerate() works:
for idx, character in enumerate('myword'):
print(f"Index={idx} character={character}")
It is worth pointing out that in this Python treats strings as arrays. When you have "abc"[0] it will return a. And, similarly, when you say 'give me each element in some array' it will simply give you the element, not the index of that element - which would be counterintuitive.

Palindrome problem - Trying to check 2 lists for equality python3.9

I'm writing a program to check if a given user input is a palindrome or not. if it is the program should print "Yes", if not "no". I realize that this program is entirely too complex since I actually only needed to check the whole word using the reversed() function, but I ended up making it quite complex by splitting the word into two lists and then checking the lists against each other.
Despite that, I'm not clear why the last conditional isn't returning the expected "Yes" when I pass it "racecar" as an input. When I print the lists in line 23 and 24, I get two lists that are identical, but then when I compare them in the conditional, I always get "No" meaning they are not equal to each other. can anyone explain why this is? I've tried to convert the lists to strings but no luck.
def odd_or_even(a): # function for determining if odd or even
if len(a) % 2 == 0:
return True
else:
return False
the_string = input("How about a word?\n")
x = int(len(the_string))
odd_or_even(the_string) # find out if the word has an odd or an even number of characters
if odd_or_even(the_string) == True: # if even
for i in range(x):
first_half = the_string[0:int((x/2))] #create a list with part 1
second_half = the_string[(x-(int((x/2)))):x] #create a list with part 2
else: #if odd
for i in range(x):
first_half = the_string[:(int((x-1)/2))] #create a list with part 1 without the middle index
second_half = the_string[int(int(x-1)/2)+1:] #create a list with part 2 without the middle index
print(list(reversed(second_half)))
print(list(first_half))
if first_half == reversed(second_half): ##### NOT WORKING BUT DONT KNOW WHY #####
print("Yes")
else:
print("No")
Despite your comments first_half and second_half are substrings of your input, not lists. When you print them out, you're converting them to lists, but in the comparison, you do not convert first_half or reversed(second_half). Thus you are comparing a string to an iterator (returned by reversed), which will always be false.
So a basic fix is to do the conversion for the if, just like you did when printing the lists out:
if list(first_half) == list(reversed(second_half)):
A better fix might be to compare as strings, by making one of the slices use a step of -1, so you don't need to use reversed. Try second_half = the_string[-1:x//2:-1] (or similar, you probably need to tweak either the even or odd case by one). Or you could use the "alien smiley" slice to reverse the string after you slice it out of the input: second_half = second_half[::-1].
There are a few other oddities in your code, like your for i in range(x) loop that overwrites all of its results except the last one. Just use x - 1 in the slicing code and you don't need that loop at all. You're also calling int a lot more often than you need to (if you used // instead of /, you could get rid of literally all of the int calls).

How to count number of substrings in python, if substrings overlap?

The count() function returns the number of times a substring occurs in a string, but it fails in case of overlapping strings.
Let's say my input is:
^_^_^-_-
I want to find how many times ^_^ occurs in the string.
mystr=input()
happy=mystr.count('^_^')
sad=mystr.count('-_-')
print(happy)
print(sad)
Output is:
1
1
I am expecting:
2
1
How can I achieve the desired result?
New Version
You can solve this problem without writing any explicit loops using regex. As #abhijith-pk's answer cleverly suggests, you can search for the first character only, with the remainder being placed in a positive lookahead, which will allow you to make the match with overlaps:
def count_overlapping(string, pattern):
regex = '{}(?={})'.format(re.escape(pattern[:1]), re.escape(pattern[1:]))
# Consume iterator, get count with minimal memory usage
return sum(1 for _ in re.finditer(regex, string))
[IDEOne Link]
Using [:1] and [1:] for the indices allows the function to handle the empty string without special processing, while using [0] and [1:] for the indices would not.
Old Version
You can always write your own routine using the fact that str.find allows you to specify a starting index. This routine will not be very efficient, but it should work:
def count_overlapping(string, pattern):
count = 0
start = -1
while True:
start = string.find(pattern, start + 1)
if start < 0:
return count
count += 1
[IDEOne Link]
Usage
Both versions return identical results. A sample usage would be:
>>> mystr = '^_^_^-_-'
>>> count_overlapping(mystr, '^_^')
2
>>> count_overlapping(mystr, '-_-')
1
>>> count_overlapping(mystr, '')
9
>>> count_overlapping(mystr, 'x')
0
Notice that the empty string is found len(mystr) + 1 times. I consider this to be intuitively correct because it is effectively between and around every character.
you can use regex for a quick and dirty solution :
import re
mystr='^_^_^-_-'
print(len(re.findall('\^(?=_\^)',mystr)))
You need something like this
def count_substr(string,substr):
n=len(substr)
count=0
for i in range(len(string)-len(substr)+1):
if(string[i:i+len(substr)] == substr):
count+=1
return count
mystr=input()
print(count_substr(mystr,'121'))
Input: 12121990
Output: 2

recursion not stopping with 'if'

I am trying to write a code which prints True if given string has at max 2 consecutive c, and at max 1 b. I am using recursion to reduce the string and check that at max 'c' is present in the same index twice.But my recursion is not stopping till it empties the whole list. Can you please suggest what's wrong with my code. Thanks!
def stringcond(N,count=0,k=0):
N=list(N)
if(N.count('b')>1):
return False
if len(N)<2:
return True
else:
for i,j in enumerate(N):
if(j=='c'):
del N[i]
count+=1
if(k==i and count>2):
return False
stringcond(N,count=count,k=i)
return True
You have several mistakes. First, why are you splitting the characters into a list? There is a perfectly good count method for strings.
Your recursion fails because you ignore the return value. You would want something like
if not stringcond(N,count=count,k=i):
return False
# I make no claim that this logic is correct.
In any case, there is no need to recur. Use count to check the quantity of "b" and many-'c' substrings:
def stringcond(s, c_max=0):
return s.count('b') <= 1 and \
s.count("c" * (c_max+1)) == 0
You have to use the result of the stringcond call. Now your function will only return whatever was determined on the top level call.

finding DNA codon starting with a or t with regular expression

Given a DNA sequence of codons, I want to get the precentage of codons starting with A or T.
The DNA sequence would be something like: dna = "atgagtgaaagttaacgt". Eeach sequence starting in the 0,3,6 etc. positions <-and that's the source of the problem as far as my intentions goes
What we wrote and works:
import re
DNA = "atgagtgaaagttaacgt"
def atPct(dna):
'''
gets a dna sequence and returns the %
of sequences that are starting with a or t
'''
numOfCodons = re.findall(r'[a|t|c|g]{3}',dna) # [a|t][a|t|c|g]{2} won't give neceseraly in the pos % 3==0 subseq
count = 0
for x in numOfCodons:
if str(x)[0]== 'a' or str(x)[0]== 't':
count+=1
print(str(x))
return 100*count/len(numOfCodons)
print(atPct(DNA))
My goal is to find it without that for loop, somehow I feel there's a way more elegant way to do this just with regular expressions but I might be wrong, if there's a better way i would be glad to learn how! is there a way to cross the location and "[a|t][a|t|c|g]{2}" as a regular expression?
p.s question assume it's a valid dna sequence that's why i haven't even checked that
A loop will be faster than doing it another way. Still, you can use sum and a generator expression (another SO answer) to improve readability:
import re
def atPct(dna):
# Find all sequences
numSeqs = re.findall('[atgc]{3}', DNA)
# Count all sequences that start with 'a' or 't'
atSeqs = sum(1 for seq in numSeqs if re.match('[at]', seq))
# Return the calculation
return 100 * len(numSeqs) / atSeqs
DNA = "atgagtgaaagttaacgt"
print( atPct(DNA) )
So you just want to find out the percentage of times a or t appear in the first of every three characters in the string? Use the step parameter of a slice:
def atPct(dna):
starts = dna[::3] # Every third character of dna, starting with the first
return (starts.count('a') + starts.count('t')) / len(starts)

Resources