I have the following function but it doesn't give me the intended result:
def GetNthLetters(text,n):
builtstring=""
for letter in text:
if text.index(letter)%n==0:
builtstring=builtstring+letter
print letter
return builtstring
str.index() finds the first match for your letter. If you have a letter that appears more than once, that'll give you the wrong index. For any given character, you only test if their first occurrence in the string is at a n'th position.
To demonstrate, take a look at the string 'hello world' with the character indices (I used . to mark the space):
0 1 2 3 4 5 6 7 8 9 10
h e l l o . w o r l d
For the letter l, text.index('l') will return 2, so it'll only be included in the output if n is 1 or 2. It doesn't matter that l also appears at index 3 or 9, because you only ever test 2 % n == 0. The same applies for 'o' (positions 4 and 7), only 4 % n == 0 is tested for either.
You could use the enumerate() function to give you a running index:
def GetNthLetters(text, n):
builtstring = ""
for index, letter in enumerate(text):
if index % n == 0:
builtstring = builtstring + letter
return builtstring
Now index is correct for every letter, repeated or not.
However, it'll be much easier to use slicing:
def GetNthLetters(text, n):
return text[::n]
This takes every n'th letter too:
>>> 'foo bar baz'[::2]
'fobrbz'
>>> 'foo bar baz'[::3]
'f ra'
>>> 'foo bar baz'[::4]
'fbb'
If somebody asked me to give every nth character in a string, I wouldn't include the first character. I would rather do something like below:
def GetNthLetters(text, n):
builtstring = ""
for i in range(0, len(text)):
if (i + 1) % n == 0:
# print(text[i])
builtstring = builtstring + text[i]
return builtstring
text = '1234567890123456789012345678901234567890'
nthLetters = GetNthLetters(text, 1)
print(nthLetters)
nthLetters = GetNthLetters(text, 2)
print(nthLetters)
nthLetters = GetNthLetters(text, 3)
print(nthLetters)
nthLetters = GetNthLetters(text, 10)
print(nthLetters)
nthLetters = GetNthLetters(text, 40)
print(nthLetters)
This would yield these results:
1234567890123456789012345678901234567890
24680246802468024680
3692581470369
0000
0
Using Python's slicing syntax:
Python's slicing syntax is much like the range() function. It accepts a start, stop and step value:
string[start : stop : step]
where you can leave any of the parameters blank and they will default to 0, the length of the string and 1 respectively.
This means you can do:
string[::n]
to get a string's every nth characterter.
So you can write the function as:
def getNthLetters(text, n):
return text[::n]
Hope this does what you want!
string = "12345678"
n = 2
splitted_string = string[::n]
print(splitted_string)
# Output : 1357
Hope this will help.!
The problem with the code is everytime the index of same repeated letter will give same result.
For example 'Hello World!'.index('o') will be always 4 so it will not give intended result.
The best way is to enumerate the for loop. so you will get appropriate index.
You should also remember array starts with 0 not 1.
Related
I'm trying to find the first repeated character in my string and output that character using python. When checking my code, I can see I'm not index the last character of my code.
What am I doing wrong?
letters = 'acbdc'
for a in range (0,len(letters)-1):
#print(letters[a])
for b in range(0, len(letters)-1):
#print(letters[b])
if (letters[a]==letters[b]) and (a!=b):
print(b)
b=b+1
a=a+1
You can do this in an easier way:
letters = 'acbdc'
found_dict = {}
for i in letters:
if i in found_dict:
print(i)
break
else:
found_dict[i]= 1
Output:
c
Here's a solution with sets, it should be slightly faster than using dicts.
letters = 'acbdc'
seen = set()
for letter in letters:
if letter in seen:
print(letter)
break
else:
seen.add(letter)
Here is a solution that would stop iteration as soon as it finds a dup
>>> from itertools import dropwhile
>>> s=set(); next(dropwhile(lambda c: not (c in s or s.add(c)), letters))
'c'
You should use range(0, len(letters)) instead of range(0, len(letters) - 1) because range already stops counting at one less than the designated stop value. Subtracting 1 from the stop value simply makes you skip the last character of letters in this case.
Please read the documentation of range:
https://docs.python.org/3/library/stdtypes.html#range
There were a few issues with your code...
1.Remove -1 from len(letters)
2.Move back one indent and do b = b + 1 even if you don't go into the if statement
3.Indent and do a = a + 1 in the first for loop.
See below of how to fix your code...
letters = 'acbdc'
for a in range(0, len(letters)):
# print(letters[a])
for b in range(0, len(letters)):
# print(letters[b])
if (letters[a] == letters[b]) and (a != b):
print(b)
b = b + 1
a = a + 1
Nice one-liner generator:
l = 'acbdc'
next(e for e in l if l.count(e)>1)
Or following the rules in the comments to fit the "abba" case:
l = 'acbdc'
next(e for c,e in enumerate(l) if l[:c+1].count(e)>1)
If complexity is not an issue then this will work fine.
letters = 'acbdc'
found = False
for i in range(0, len(letters)-1):
for j in range(i+1, len(letters)):
if (letters[i] == letters[j]):
print (letters[j])
found = True
break
if (found):
break
The below code prints the first repeated character in a string. I used the functionality of the list to solve this problem.
def findChar(inputString):
list = []
for c in inputString:
if c in list:
return c
else:
list.append(c)
return 'None'
print (findChar('gotgogle'))
Working fine as well. It gives the result as 'g'.
def first_repeated_char(str1):
for index,c in enumerate(str1):
if str1[:index+1].count(c) > 1:
return c
return "None"
print(first_repeated_char("abcdabcd"))
str_24 = input("Enter the string:")
for i in range(0,len(str_24)):
first_repeated_count = str_24.count(str_24[i])
if(first_repeated_count > 1):
break
print("First repeated char is:{} and character is
{}".format(first_repeated_count,str_24[i]))
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
Define a function named nested_increasing_additions(n) which receives one positive integer (n) and returns a string as illustrated in the following examples:
If n is 3, the function should return the string:
1+..1+2+..1+2+3+..
If n is 5, the function should return the string:
1+..1+2+..1+2+3+..1+2+3+4+..1+2+3+4+5..+
What I think is, I can make n to a list [1,2,3] and use while loop or for loop to repeat n times. For the first loop it returns 1+.., for the second loop it returns 1+2.. somehow (which i don't know) it stops at 2 which is the same as the repeating time.
I don't know if I'm thinking it right. Need some help and explanations! Thank you!
Consecutive evaluations of these strings results in a sequence of tetrahedral numbers. For example, for input 5, the output evaluates to 35. This is the number of spheres you would need to build a tetrahedron of side length 5.
To see how it relates to the sum in the question, note that the discrete "volume" of the tetrahedron would be equal to the sum of the triangle "slices" from top to bottom.
35 = 1 + 3 + 6 + 10 + 15
= 1 + (1+2) + (1+2+3) + (1+2+3+4) + (1+2+3+4+5)
By a similar argument, the triangular numbers are made up of slices of consecutive integers.
Please excuse the maths, it was difficult (but not impossible) to adapt a closed-form solution into the desired output format.
def tetrahedral(n):
return n*(n+1)*(n+2)//6
def string_generator(n):
x = tetrahedral(n)
n = N = 1
while x > 0:
while n <= N:
yield str(n) + '+'
n += 1
x -= N*(N+1)//2
n = 1
N += 1
yield '..'
def nested_increasing_additions(n):
return ''.join(string_generator(n))
You can build the complete string step by step, and remember at each step what you have added last:
def nested_increasing_additions(n):
complete_string = ""
add_string = ""
for i in range(1,n+1):
add_string += str(i) + "+"
complete_string += add_string + ".."
return complete_string
print(nested_increasing_additions(1))
print(nested_increasing_additions(3))
print(nested_increasing_additions(5))
The output with python3 is:
1+..
1+..1+2+..1+2+3+..
1+..1+2+..1+2+3+..1+2+3+4+..1+2+3+4+5+..
def nested_increasing_additions(n):
l=['']
for i in range(1, n+1):
l.append(l[-1]+str(i)+'+')
return '..'.join(l[1:])
This returns a string without the .. at the end. If you want that, just do return '..'.join(l[1:]) + '..'
you can use something like this.
def nested_increasing_additions(n):
string = ""
for i in range(1,n+1): #1
for j in range(1,i+1): #2
string += str(j)+"+" #4
string += ".." #5
print(string)
here is a printout of nested_increasing_additions(4)
1+..1+2+..1+2+3+..1+2+3+4+..
i think it's self explanatory, nothing complicated.
How's this:
def nested_increasing_additions(n):
string = ""
new_string = ""
dot = ".."
for i in range(1, n+1):
new_string+=('{}+'.format(i))
string = string+new_string+dot
print(string)
return (string)
Output:
nested_increasing_additions(3)
'1+..1+2+..1+2+3+..'
Assuming you did want the ".." at the end of each returned string and that recursion is OK, here's a solution:
def nested_increasing_additions(n):
if n == 1:
return "1+.."
else:
return nested_increasing_additions(n-1) + '%s+..' % '+'.join(str(i) for i in range(1, n+1))
print(nested_increasing_additions(3))
print(nested_increasing_additions(5))
type(nested_increasing_additions(1))
Prints:
1+..1+2+..1+2+3+..
1+..1+2+..1+2+3+..1+2+3+4+..1+2+3+4+5+..
<type 'str'>
Explanation:
The first return and if (true) block ends the recursive call when the passed in argument value reaches 1 via subtraction from the other half.
The second half (else block) calls the next iteration with n subtracted by 1 and the string build of the current iteration (if n!=1).
The complicated looking code '%s+..' % '+'.join(str(i) for i in range(1, n+1)) is just concatenation of a list of numbers generated by the range function, turned into strings and "+.."
range(1, n+1) returns a list of integers starting with 1 until n+1 so range(1,3) yields [1,2]. This is passed to join which places a + between each number.
For a homework problem, we are asked to define a function that will count the number of consecutive digits in a binary string, and return the number.
For example, the function should return n = [4,8,4,3,15] for the binary input S = ‘1111000000001111000111111111111111’.
I have this so far, but I know it's not correct, and I do not know where to go from here. Any help would be appreciated!
def consecutive_length(s):
if s == '':
return 0
if s[0] == 0:
return 0
return 1 + consecutive_length(s[1:])
Note: we cannot use any loops. It is required that we do this with recursion.
Thank you!
Here's a hopefully pythonic way (ignoring the fact that it's not pythonic to solve this kind of problem recursively):
def consecutive_length(s):
def sub(idx, lst, last_char, count):
try:
c = s[idx] # c will be the 'next' char
except IndexError: # no more chars left to process
if count:
lst.append(count)
return lst
if c != last_char:
lst.append(count)
count = 0
return sub(idx+1, lst, c, count+1)
return sub(0, [], s[0] if s else None, 0)
where
the outer function just takes the string as an argument and hides the inner functions additional parameters
idx is the index to the string, we don't allocate a new string at every recursive call (and s[idx] is O(1) iirc)
instead of computing the length of the string, we wait for an exception to happen (EAFP - Easier to ask for forgiveness than permission)
Testing:
>>> print consecutive_length('1111000000001111000111111111111111')
[4, 8, 4, 3, 15]
>>> print consecutive_length('1111000000001111000111111111111110')
[4, 8, 4, 3, 14, 1]
>>> print consecutive_length('1')
[1]
>>> print consecutive_length('0')
[1]
>>> print consecutive_length('')
[]
I am assuming here the '11' is a consecutive sequence of 1's .So '111' has 2 consecutive one's. This solution is, if loops is not a problem. Use index to find '11' and keep doing it until you find no more. The below program shows the number of consecutive 1's .
cnt = 0
pos = -1
while True:
try:
pos = '111001100101111'.index('11', pos+1)
cnt += 1
except ValueError:
print cnt
break
Result:
6
EDIT: uselpa has a much better way of doing it.
Since loops aren't allowed:
def consecutive_length(s, output, prev_char, count):
# if end of string, append last count and return output
if s == '':
output.append(count)
return output
# if curr_char is same as prev_char, add 1 to count and parse next char
if s[0] == prev_char:
return consecutive_length(s[1:], output, s[0], count + 1)
# if curr_char is diff from prev_char, append count and reset count to 1
else:
prev_char = s[0]
output.append(count)
return consecutive_length(s[1:], output, s[0], 1)
Call it with consecutive_length(s, [], s[0], 0).
I want to swap each pair of characters in a string. '2143' becomes '1234', 'badcfe' becomes 'abcdef'.
How can I do this in Python?
oneliner:
>>> s = 'badcfe'
>>> ''.join([ s[x:x+2][::-1] for x in range(0, len(s), 2) ])
'abcdef'
s[x:x+2] returns string slice from x to x+2; it is safe for odd len(s).
[::-1] reverses the string in Python
range(0, len(s), 2) returns 0, 2, 4, 6 ... while x < len(s)
The usual way to swap two items in Python is:
a, b = b, a
So it would seem to me that you would just do the same with an extended slice. However, it is slightly complicated because strings aren't mutable; so you have to convert to a list and then back to a string.
Therefore, I would do the following:
>>> s = 'badcfe'
>>> t = list(s)
>>> t[::2], t[1::2] = t[1::2], t[::2]
>>> ''.join(t)
'abcdef'
Here's one way...
>>> s = '2134'
>>> def swap(c, i, j):
... c = list(c)
... c[i], c[j] = c[j], c[i]
... return ''.join(c)
...
>>> swap(s, 0, 1)
'1234'
>>>
''.join(s[i+1]+s[i] for i in range(0, len(s), 2)) # 10.6 usec per loop
or
''.join(x+y for x, y in zip(s[1::2], s[::2])) # 10.3 usec per loop
or if the string can have an odd length:
''.join(x+y for x, y in itertools.izip_longest(s[1::2], s[::2], fillvalue=''))
Note that this won't work with old versions of Python (if I'm not mistaking older than 2.5).
The benchmark was run on python-2.7-8.fc14.1.x86_64 and a Core 2 Duo 6400 CPU with s='0123456789'*4.
If performance or elegance is not an issue, and you just want clarity and have the job done then simply use this:
def swap(text, ch1, ch2):
text = text.replace(ch2, '!',)
text = text.replace(ch1, ch2)
text = text.replace('!', ch1)
return text
This allows you to swap or simply replace chars or substring.
For example, to swap 'ab' <-> 'de' in a text:
_str = "abcdefabcdefabcdef"
print swap(_str, 'ab','de') #decabfdecabfdecabf
Loop over length of string by twos and swap:
def oddswap(st):
s = list(st)
for c in range(0,len(s),2):
t=s[c]
s[c]=s[c+1]
s[c+1]=t
return "".join(s)
giving:
>>> s
'foobar'
>>> oddswap(s)
'ofbora'
and fails on odd-length strings with an IndexError exception.
There is no need to make a list. The following works for even-length strings:
r = ''
for in in range(0, len(s), 2) :
r += s[i + 1] + s[i]
s = r
A more general answer... you can do any single pairwise swap with tuples or strings using this approach:
# item can be a string or tuple and swap can be a list or tuple of two
# indices to swap
def swap_items_by_copy(item, swap):
s0 = min(swap)
s1 = max(swap)
if isinstance(item,str):
return item[:s0]+item[s1]+item[s0+1:s1]+item[s0]+item[s1+1:]
elif isinstance(item,tuple):
return item[:s0]+(item[s1],)+item[s0+1:s1]+(item[s0],)+item[s1+1:]
else:
raise ValueError("Type not supported")
Then you can invoke it like this:
>>> swap_items_by_copy((1,2,3,4,5,6),(1,2))
(1, 3, 2, 4, 5, 6)
>>> swap_items_by_copy("hello",(1,2))
'hlelo'
>>>
Thankfully python gives empty strings or tuples for the cases where the indices refer to non existent slices.
To swap characters in a string a of position l and r
def swap(a, l, r):
a = a[0:l] + a[r] + a[l+1:r] + a[l] + a[r+1:]
return a
Example:
swap("aaabcccdeee", 3, 7) returns "aaadcccbeee"
Do you want the digits sorted? Or are you swapping odd/even indexed digits? Your example is totally unclear.
Sort:
s = '2143'
p=list(s)
p.sort()
s = "".join(p)
s is now '1234'. The trick is here that list(string) breaks it into characters.
Like so:
>>> s = "2143658709"
>>> ''.join([s[i+1] + s[i] for i in range(0, len(s), 2)])
'1234567890'
>>> s = "badcfe"
>>> ''.join([s[i+1] + s[i] for i in range(0, len(s), 2)])
'abcdef'
re.sub(r'(.)(.)',r"\2\1",'abcdef1234')
However re is a bit slow.
def swap(s):
i=iter(s)
while True:
a,b=next(i),next(i)
yield b
yield a
''.join(swap("abcdef1234"))
One more way:
>>> s='123456'
>>> ''.join([''.join(el) for el in zip(s[1::2], s[0::2])])
'214365'
>>> import ctypes
>>> s = 'abcdef'
>>> mutable = ctypes.create_string_buffer(s)
>>> for i in range(0,len(s),2):
>>> mutable[i], mutable[i+1] = mutable[i+1], mutable[i]
>>> s = mutable.value
>>> print s
badcfe
def revstr(a):
b=''
if len(a)%2==0:
for i in range(0,len(a),2):
b += a[i + 1] + a[i]
a=b
else:
c=a[-1]
for i in range(0,len(a)-1,2):
b += a[i + 1] + a[i]
b=b+a[-1]
a=b
return b
a=raw_input('enter a string')
n=revstr(a)
print n
A bit late to the party, but there is actually a pretty simple way to do this:
The index sequence you are looking for can be expressed as the sum of two sequences:
0 1 2 3 ...
+1 -1 +1 -1 ...
Both are easy to express. The first one is just range(N). A sequence that toggles for each i in that range is i % 2. You can adjust the toggle by scaling and offsetting it:
i % 2 -> 0 1 0 1 ...
1 - i % 2 -> 1 0 1 0 ...
2 * (1 - i % 2) -> 2 0 2 0 ...
2 * (1 - i % 2) - 1 -> +1 -1 +1 -1 ...
The entire expression simplifies to i + 1 - 2 * (i % 2), which you can use to join the string almost directly:
result = ''.join(string[i + 1 - 2 * (i % 2)] for i in range(len(string)))
This will work only for an even-length string, so you can check for overruns using min:
N = len(string)
result = ''.join(string[min(i + 1 - 2 * (i % 2), N - 1)] for i in range(N))
Basically a one-liner, doesn't require any iterators beyond a range over the indices, and some very simple integer math.
While the above solutions do work, there is a very simple solution shall we say in "layman's" terms. Someone still learning python and string's can use the other answers but they don't really understand how they work or what each part of the code is doing without a full explanation by the poster as opposed to "this works". The following executes the swapping of every second character in a string and is easy for beginners to understand how it works.
It is simply iterating through the string (any length) by two's (starting from 0 and finding every second character) and then creating a new string (swapped_pair) by adding the current index + 1 (second character) and then the actual index (first character), e.g., index 1 is put at index 0 and then index 0 is put at index 1 and this repeats through iteration of string.
Also added code to ensure string is of even length as it only works for even length.
DrSanjay Bhakkad post above is also a good one that works for even or odd strings and is basically doing the same function as below.
string = "abcdefghijklmnopqrstuvwxyz123"
# use this prior to below iteration if string needs to be even but is possibly odd
if len(string) % 2 != 0:
string = string[:-1]
# iteration to swap every second character in string
swapped_pair = ""
for i in range(0, len(string), 2):
swapped_pair += (string[i + 1] + string[i])
# use this after above iteration for any even or odd length of strings
if len(swapped_pair) % 2 != 0:
swapped_adj += swapped_pair[-1]
print(swapped_pair)
badcfehgjilknmporqtsvuxwzy21 # output if the "needs to be even" code used
badcfehgjilknmporqtsvuxwzy213 # output if the "even or odd" code used
One of the easiest way to swap first two characters from a String is
inputString = '2134'
extractChar = inputString[0:2]
swapExtractedChar = extractChar[::-1] """Reverse the order of string"""
swapFirstTwoChar = swapExtractedChar + inputString[2:]
# swapFirstTwoChar = inputString[0:2][::-1] + inputString[2:] """For one line code"""
print(swapFirstTwoChar)
#Works on even/odd size strings
str = '2143657'
newStr = ''
for i in range(len(str)//2):
newStr += str[i*2+1] + str[i*2]
if len(str)%2 != 0:
newStr += str[-1]
print(newStr)
#Think about how index works with string in Python,
>>> a = "123456"
>>> a[::-1]
'654321'