If we have a string of alphabetical characters and some dashes, and we want to count the number of dashes between any two alphabetic characters in this string. what is the easiest way to do this?
Example:
Input: a--bc---d-k
output: 2031
This means that there are 2 dashes between a and b, 0 dash between b and c, 3 dashes between c and d and 1 dash between d and k
what is a good way to find this output list in python?
You can use a very simple solution like this:
import re
s = 'a--bc---d-k'
# Create a list of dash strings.
dashes = re.split('[a-z]', s)[1:-1]
# Measure the length of each dash string in the list and join as a string.
results = ''.join([str(len(i)) for i in dashes])
Output:
'2031'
Solution with regex:
import re
x = 'a--bc---d-k'
results = [
len(m) for m in
re.findall('(?<=[a-z])-*(?=[a-z])', x)
]
print(results)
print(''.join(str(r) for r in results))
output:
[2, 0, 3, 1]
2031
Solution with brute force loop logic:
x = 'a--bc---d-k'
count = 0
results = []
for c in x:
if c == '-':
count += 1
else:
results.append(count)
count = 0
results = results[1:] # cut off first length
print(results)
output:
[2, 0, 3, 1]
If you input may also begin with a dash, you could use this:
def count_dashes(string):
all_counts = []
dash_count = 0
for char in string:
if char == "-":
dash_count += 1
else:
all_counts.append(dash_count)
dash_count = 0
return all_counts
But if your input always starts with a letter, you may not like the 0 that's always at the head of the list.
If you need the output as a string of ints, then you could add this:
def count_dashes(string):
all_counts = []
dash_count = 0
for char in string:
if char == "-":
dash_count += 1
else:
all_counts.append(dash_count)
dash_count = 0
return "".join([str(number) for number in all_counts])
Here's a simple loop approach:
myinput = 'a--bc---d-k'
output = []
output_count = -1
for elem in myinput:
if elem == '-':
output[output_count] = output[output_count]+1
else:
output.append(0)
output_count += 1
print(output)
Related
Task:
Given an integer as input, Add code to take the individual digits and increase by 1.
For example, if the digit is 5, then it becomes 6. Please note that if the digit is 9 it becomes 0.
More examples
input: 2342 output: 3453
input: 9999 output: 0
input: 835193 output: 946204
I wrote this function but I know for sure this isn't way to write this code and I'm looking for some tips to write it in a more concise, efficient way. Please advise.
def new_num (num):
newnum = []
for i in range (0,len(str(num))):
upper = num%10
print(upper)
num = int(num/10)
print(num)
if upper == 9:
upper = 0
newnum.append(upper)
else:
upper+=1
newnum.append(upper)
strings = [str(newnum) for newnum in newnum]
a_string = "".join(strings)
an_integer = str(a_string)
new_int = int(an_integer[::-1])
return(new_int)
You could do this:-
n = '2349'
nn = ''
for i in n:
nn += '0' if i == '9' else str(int(i) + 1)
print(nn)
one of many possible improvements... replace the if/else with:
upper = (upper+1)%10
newnum.append(upper)
x= input('no = ')
x= '' + x
ans=[]
for i in x :
if int(i) == 9 :
ans.append(str(0))
else:
ans.append(str(int(i)+1))
ans=''.join(ans)
if int(ans) == 0:
ans = 0
print(ans.strip('0'))
This is the most basic code I can write, it can also be shortened to few lines
testInputs = [2342, 9999, 835193, 9]
def new_num (num):
return int("".join([str((int(d) + 1) % 10) for d in str(num)]))
result = [new_num(test) for test in testInputs]
print(result)
# [3453, 0, 946204, 0]
convert the num to string
convert the digit by using (int(d) + 1) % 10
join back the digits
parse the string as int
def newnum(x):
lis = list(str(x))
new_list = [int(i)+1 if int(i)<9 else 0 for i in lis]
new_list = map(str,new_list)
return int(''.join(new_list))
Take the number and convert to list of strings
Iterate through the list. Convert each element to int and add 1. The condition of digit 9 is included to produce 0 instead of 10
Map it back to strings and use join.
Return the output as int.
I want to find out how often does "reindeer" (in any order) come in a random string and what is the left over string after "reindeer" is removed. I need to preserve order of the left over string
So for example
"erindAeer" -> A (reindeer comes 1 time)
"ierndeBeCrerindAeer" -> ( 2 reindeers, left over is BCA)
I thought of sorting and removing "reindeer", but i need to preserve the order . What's a good way to do this?
We can replace those letters after knowing how many times they repeat, and Counter is convenient for counting elements.
from collections import Counter
def leftover(letter_set, string):
lcount, scount = Counter(letter_set), Counter(string)
repeat = min(scount[l] // lcount[l] for l in lcount)
for l in lcount:
string = string.replace(l, "", lcount[l] * repeat)
return f"{repeat} {letter_set}, left over is {string}"
print(leftover("reindeer", "ierndeBeCrerindAeer"))
print(leftover("reindeer", "ierndeBeCrerindAeere"))
print(leftover("reindeer", "ierndeBeCrerindAee"))
Output:
2 reindeer, left over is BCA
2 reindeer, left over is BCAe
1 reindeer, left over is BCerindAee
Here is a rather simple approach using collections.Counter:
from collections import Counter
def purge(pattern, string):
scount, pcount = Counter(string), Counter(pattern)
cnt = min(scount[x] // pcount[x] for x in pcount)
scount.subtract(pattern * cnt)
return cnt, "".join(scount.subtract(c) or c for c in string if scount[c])
>>> purge("reindeer", "ierndeBeCrerindAeer")
(2, 'BCA')
Here is the code in Python:
def find_reindeers(s):
rmap = {}
for x in "reindeer":
if x not in rmap:
rmap[x] = 0
rmap[x] += 1
hmap = {key: 0 for key in "reindeer"}
for x in s:
if x in "reindeer":
hmap[x] += 1
total_occ = min([hmap[x]//rmap[x] for x in "reindeer"])
left_over = ""
print(hmap, rmap)
for x in s:
if (x in "reindeer" and hmap[x] > total_occ * rmap[x]) or (x not in "reindeer"):
left_over += x
return total_occ, left_over
print(find_reindeers("ierndeBeCrerindAeer"))
Output for ierndeBeCrerindAeer:
(2, "BCA")
You can do it by using count and replace string function:
import queue
word = "reindeer"
given_string = "ierndeBeCrerindAeer"
new_string = ""
counter = 0
tmp = ""
letters = queue.Queue()
for i in given_string:
if not i in word:
new_string += i
else:
letters.put(i)
x = 0
while x < len(word):
while not letters.empty():
j = letters.get()
if j == word[x]:
tmp += j
# print(tmp)
break
else:
letters.put(j)
x = x +1
if tmp == word:
counter += 1
tmp = ""
x = 0
print(f"The word {word} occurs {counter} times in the string {given_string}.")
print("The left over word is",new_string)
Output will be:
The word reindeer occurs 2 times in the string ierndeBeCrerindAeer.
The left over word is BCA
It's easy to use queue here so that we don't repeat the elements that are already present or found.
Hope this answers your question, Thank you!
I have written this function which is supposed to go through a user-provided string like 1-3-5, and output a corresponding series of letters, where A is assigned to 1, B is assigned to 2, C is assigned to 3, etc. So in the case of 1-3-5 the output would be ACE. For 2-3-4, it should print BCD. For ?-3-4 or --3-4 it should still print BCD. Here is the code I have written so far:
def number_to_letter(encoded):
result = ""
start = 0
for char in range(len(encoded)):
if encoded[char] == '-':
i = encoded.index("-")
sub_str = encoded[start:i]
if not sub_str.isdigit():
result += ""
else:
letter = chr(64 + int(sub_str))
if 0 < int(sub_str) < 27:
result += letter
else:
result += ""
start += len(sub_str) + 1
return result
print(num_to_let('4-3-25'))
My output is D, when it should be DCY. I am trying to do this without using any lists or using the split function, just by finding the - character in the sub-string and converting the numbers before it into a letter. What can I do?
You can try doing something like this:
def number_to_letter(encoded):
result = ""
buffer = ""
for ch in encoded:
if ch == '-':
if buffer and 0 < int(buffer) < 27:
result += chr(64 + int(buffer))
buffer = ""
elif ch.isdigit():
buffer += ch
else:
if buffer and 0 < int(buffer) < 27:
result += chr(64 + int(buffer))
return result
print(number_to_letter('1-3-5'))
output:
ACE
Explanation:
we loop for each character and add it to some buffer. when we encounter - (delimiter) we try to parse the buffer and reset it. And we do the same parsing at the end one more time and return the result.
The way the validation works is that, whenever we populate the buffer we check for number validity (using .isdigit()) and when we parse the buffer we check for the range constraints.
import string
alphabet = list(string.ascii_lowercase)
combination = "1-2-3"
def seperate(s, sep='-'):
return [s[:s.index(sep)]] + seperate(s[s.index(sep)+1:]) if sep in s else [s]
combination = seperate(combination)
print("".join([alphabet[int(i)-1] for i in combination]))
the approach of this code is to find the first '-' and then store where it is so next time we can look for the first '-' after the last one
when the comments in my code talk about a cycle means going through the loop (While looping:) once
def number_to_letter(encoded):
letterString = ""
startSubStr = 0
endSubStr = 0
looping = True
while looping:
if endSubStr > (len(encoded)-4):# if we're at the last number we don't look for '-'. we go to the end of the str and end the loop
endSubStr = len(encoded)
looping = False
else:
endSubStr = encoded.index('-', startSubStr) #find the first '-' after the '-' found in the last cycle
number = int(encoded[startSubStr:endSubStr]) #get the number between the '-' found in the last cycle through this loop and the '-' found in this one
if number < 27:
letter = chr(64 + int(number))
letterString += letter
startSubStr = endSubStr + 1 #set the start of the substring to the end so the index function doesn't find the '-' found in this cycle again
return letterString
print(number_to_letter("23-1-1-2")) #>>> WAAB
result:
WAAB
I see you don't want to use split, how about filter? ;)
import itertools
s = '1-2-3'
values = [''.join(e) for e in filter(
lambda l: l != ['-'],
[list(g) for k, g in itertools.groupby(
[*s], lambda s: s.isnumeric()
)
]
)
]
That will essentially do what .split('-') does on s. Also list(s) will behave the same as [*s] if you wanna use that instead.
Now you can just use ord and chr to construct the string you require-
start_pivot = ord('A') - 1
res = ''.join([chr(int(i) + start_pivot) for i in values])
Output
>>> s = '2-3-4'
>>> values = [''.join(e) for e in filter(
...: lambda l: l != ['-'],
...: [list(g) for k, g in itertools.groupby(
...: [*s], lambda s: s.isnumeric()
...: )
...: ]
...: )
...: ]
>>> start_pivot = ord('A') - 1
>>> res = ''.join([chr(int(i) + start_pivot) for i in values])
>>> res
'BCD'
No lists, no dicts. What about RegExp?
import re
def get_letter(n):
if int(n) in range(1,27): return chr(int(n)+64)
def number_to_letter(s):
return re.sub(r'\d+', lambda x: get_letter(x.group()), s).replace('-','')
print(number_to_letter('1-2-26')) # Output: ABZ
No lists, okay. But what about dicts?
def abc(nums):
d = {'-':'','1':'A','2':'B','3':'C','4':'D','5':'E','6':'F','7':'G','8':'H','9':'I','0':'J'}
res = ''
for n in nums: res += d[n]
return res
print(abc('1-2-3-9-0')) # Output: ABCIJ
Here is a corrected version:
def abc(nums):
d = {'-':'','1':'A','2':'B','3':'C','4':'D','5':'E','6':'F','7':'G','8':'H','9':'I','0':'J'}
res = ''
for n in nums:
if n in d:
res += d[n]
return res
print(abc('?-2-3-9-0')) # Output: BCIJ
This question already has answers here:
Count consecutive characters
(15 answers)
Closed 3 years ago.
input = 'XXYXYYYXYXXYYY'
output = [2,1,1,3,1,1,2,3]
How would count the number of X's and Y's in a string in the order that they are inputted and then put those values in a list?
import itertools
numbers = []
input = 'XXYXYYYXYXXYYY'
split_string = [''.join(g) for k, g in itertools.groupby(input)]
for i in split_string:
numbers.append(len(i))
print(numbers)
Output:
[2, 1, 1, 3, 1, 1, 2, 3]
You could do this using a while loop by iterating the whole list.
str = 'XXYXYYYXYXXYYY';
i = 0
output = []
k = 1
while i < len(str) - 1:
if str[i] == str[i+1]:
k = k + 1
else:
output.append(k)
k = 1
i = i + 1
output.append(k)
print(output)
Output
[2, 1, 1, 3, 1, 1, 2, 3]
Try using itertools.groupby:
from itertools import groupby
s = 'XXYXYYYXYXXYYY'
print([len(list(i)) for _, i in groupby(s)])
Short solution using regex
import re
s = 'XXYXYYYXYXXYYY'
l = [len(m.group()) for m in re.finditer(r'(.)\1*', s)]
Based on this answer
Here's what you can try
test = 'XXYXYYYXYXXYYY'
count = 1
result_list = list()
prev_char = test[0]
for char in test[1:]:
if char == prev_char:
count+=1
prev_char = char
else:
result_list.append(count)
count=1
prev_char = char
result_list.append(count)
print(result_list)
Output
[2, 1, 1, 3, 1, 1, 2, 3]
Without any libs it will be like this:
string = 'XXYXYYYXYXXYYY'
res = []
current = ''
for char in string:
if current == char:
res[-1] += 1
else:
res.append(1)
current = char
print('res', res) # [2,1,1,3,1,1,2,3]
Try This.
input1 = 'XXYXYYYXYXXYYY'
output_list = []
count = 1
for index in range(len(input1)-1):
if input1[index] == input1[index+1]:
count += 1
else:
output_list.append(count)
count = 1
if input1[-1] == input1[-2]:
output_list[-1] += 1
else:
output_list.append(1)
print(output_list)
The basic approach is to occurrences and stop if new char come. Code is below.
list_of_consec = []
def consec_occur(strr):
i = 0
cc = []
while ( i < len(strr) -1 ):
count =1
while strr[i] == strr[i+1]:
i += 1
count += 1
if i + 1 == len(strr):
break
cc.append(count)
i += 1
return (cc)
if __name__ == "__main__":
print(consec_occur('XXYXYYYXYXXYYY'))
You can change the code according to your need. If you want list then make cc global and remove return statement and in print statement use cc.
I am trying to make a string alternate between upper and lower case letters. My current code is this:
def skyline (str1):
result = ''
index = 0
for i in str1:
result += str1[index].upper() + str1[index + 1].lower()
index += 2
return result
When I run the above code I get an error saying String index out of range. How can I fix this?
One way using below with join + enumerate:
s = 'asdfghjkl'
''.join(v.upper() if i%2==0 else v.lower() for i, v in enumerate(s))
#'AsDfGhJkL'
This is the way I would rewrite your logic:
from itertools import islice, zip_longest
def skyline(str1):
result = ''
index = 0
for i, j in zip_longest(str1[::2], islice(str1, 1, None, 2), fillvalue=''):
result += i.upper() + j.lower()
return result
res = skyline('hello')
'HeLlO'
Explanation
Use itertools.zip_longest to iterate chunks of your string.
Use itertools.islice to extract every second character without building a separate string.
Now just iterate through your zipped iterable and append as before.
Try for i in range(len(str1)): and substitute index for i in the code. After, you could do
if i % 2 == 0: result += str1[i].upper()
else: result += str1[i].lower()
For every character in your input string, you are incrementing the index by 2. That's why you are going out of bounds.
Try using length of string for that purpose.
you do not check if your index is still in the size of your string.
It would be necessary to add a condition which verifies if the value of i is always smaller than the string and that i% 2 == 0 and that i == 0 to put the 1st character in Upper
with i% 2 == 0 we will apply the upper one letter on two
for i, __ in enumerate(str1):
if i+1 < len(str1) and i % 2 == 0 or i == 0:
result += str1[i].upper() + str1[i + 1].lower()
I tried to modify as minimal as possible in your code, so that you could understand properly. I just added a for loop with step 2 so that you wouldn't end up with index out of range. And for the final character in case of odd length string, I handled separately.
def skyline (str1):
result = ''
length = len(str1)
for index in range(0, length - 1, 2):
result += str1[index].upper() + str1[index + 1].lower()
if length % 2 == 1:
result += str1[length - 1].upper()
return result
You can use the following code:
def myfunc(str1):
result=''
for i in range(0,len(str1)):
if i % 2 == 0:
result += str1[i].upper()
else:
result += str1[i].lower()
return result
in your code you are get 2 word by one time so you should divide your loop by 2 because your loop work by depending your input string so make an variable like peak and equal it to len(your input input) then peak = int(peak/2) it will solve your pr
def func(name):
counter1 = 0
counter2 = 1
string = ''
peak = len(name)
peak = int(peak/2)
for letter in range(1,peak+1):
string += name[counter1].lower() + name[counter2].upper()
counter1 +=2
counter2 +=2
return string