How to reverse and concatenate strings at certain indexes? - python

For my assignment, I'm required to first come up with a function that reverses a string that is inputted (which I've already done using the code below)
def reverse(s):
if len(s) <= 1:
return s
return reverse(s[1:]) + s[0]
The next part is to construct a new string from a given one by breaking it at a certain index value, and concatenating the reverse of the second part (the suffix) to the beginning of the first part (the prefix)
For example, if the input string is 'laptop' and the chosen index value is, say, 3, the string is broken as 'lap' + 'top'. 'top' would then be reversed to 'pot' and would be concatenated with the prefix (in the order) as 'pot' + 'lap'
The assignment is somewhat confusing and since I'm a novice with little to no experience besides a couple of days working in Python, I'm a little confused as to what to do. I'm pretty sure I have to use the slice and concatenation operators but I'm not sure how I should go about constructing a function that suits the above criteria. Any pointers?

Combining the other two answers, and implementing your reverse function:
def concatreverse(s, i):
"""This function takes in a string, s, which
is split at an index, i, reverses the second of the split,
and concatenates it back on to the first part"""
#Takes your inputs and processes
part1,part2 = s[0:i], s[i:]
#Reverse part2 with the function you already created
#this assumes it is accessible (in the same file, for instance)
rev_part2 = reverse(part2)
#concatenate the result
result = part1 +rev_part2
#Give it back to the caller
return result
As a beginner, it helps to step through line by line, or doing tests using the interpreter to see exactly what's going on :)

Something like:
def concatreverse(s, i):
return s[:i] + reverse(s[i:])

You could do as follows:
s = 'laptop'
i = 3;
# split the string into two parts
part1,part2 = s[0:i], s[i:]
# make new string starting with reversed second part.
s2 = part2[::-1] + part1
print(s2)
# prints: potlap

Related

assigning slices to strings

I've looked around for an answer/solution for this question for a bit, as it seems like it should have been asked already. But I have failed to find anything about reassigning a slice. I'm doing one of the quizzes for the online code teacher Treehouse, and they have given me this question/assignment:
I need you to create a new function for me.
This one will be named sillycase and it'll take a single string as an argument.
sillycase should return the same string but the first half should be lowercased and the second half should be uppercased.
For example, with the string "Treehouse", sillycase would return "treeHOUSE".
Don't worry about rounding your halves, but remember that indexes should be
integers. You'll want to use the int() function or integer division, //.
I've worked off of other people's questions and gotten this far:
def sillycase(example):
begining = example[:len(example) // 2]
end = example[len(example) // 2:]
begining.lower()
end.upper()
example = begining + end
return example
I'm not sure why that is wrong, but when I run it with example being "Treehouse", it returns "Treehouse". If not clear yet my question is how to get the first half of a string lowercased, and the second half uppercased.
The methods .lower() and .upper() for strings return a new string and don't work in-place. The following should work which adds the new strings returned by lower and upper directly:
def sillycase(example):
beginning = example[:len(example) // 2]
end = example[len(example) // 2:]
example = beginning.lower() + end.upper()
return example
sillycase('treehouse') # 'treeHOUSE'
You need to assign .lower() and .upper() to the variables, for example:
begining = begining.lower()
end = end.upper()
example = begining + end
or in your case:
def sillycase(example):
begining = example[:len(example) // 2].lower()
end = example[len(example) // 2:].upper()
example = begining + end
return example
Strings are immutable! When you do
begining.lower()
end.upper()
begining and end are not changed , they just simply return you the lower and uppercase strings respectively. So in order to get the result you are expecting do something like this
begining = begining.lower()
end = end.upper()

The number of differences between characters in a string in Python 3

Given a string, lets say "TATA__", I need to find the total number of differences between adjacent characters in that string. i.e. there is a difference between T and A, but not a difference between A and A, or _ and _.
My code more or less tells me this. But when a string such as "TTAA__" is given, it doesn't work as planned.
I need to take a character in that string, and check if the character next to it is not equal to the first character. If it is indeed not equal, I need to add 1 to a running count. If it is equal, nothing is added to the count.
This what I have so far:
def num_diffs(state):
count = 0
for char in state:
if char != state[char2]:
count += 1
char2 += 1
return count
When I run it using num_diffs("TATA__") I get 4 as the response. When I run it with num_diffs("TTAA__") I also get 4. Whereas the answer should be 2.
If any of that makes sense at all, could anyone help in fixing it/pointing out where my error lies? I have a feeling is has to do with state[char2]. Sorry if this seems like a trivial problem, it's just that I'm totally new to the Python language.
import operator
def num_diffs(state):
return sum(map(operator.ne, state, state[1:]))
To open this up a bit, it maps !=, operator.ne, over state and state beginning at the 2nd character. The map function accepts multible iterables as arguments and passes elements from those one by one as positional arguments to given function, until one of the iterables is exhausted (state[1:] in this case will stop first).
The map results in an iterable of boolean values, but since bool in python inherits from int you can treat it as such in some contexts. Here we are interested in the True values, because they represent the points where the adjacent characters differed. Calling sum over that mapping is an obvious next step.
Apart from the string slicing the whole thing runs using iterators in python3. It is possible to use iterators over the string state too, if one wants to avoid slicing huge strings:
import operator
from itertools import islice
def num_diffs(state):
return sum(map(operator.ne,
state,
islice(state, 1, len(state))))
There are a couple of ways you might do this.
First, you could iterate through the string using an index, and compare each character with the character at the previous index.
Second, you could keep track of the previous character in a separate variable. The second seems closer to your attempt.
def num_diffs(s):
count = 0
prev = None
for ch in s:
if prev is not None and prev!=ch:
count += 1
prev = ch
return count
prev is the character from the previous loop iteration. You assign it to ch (the current character) at the end of each iteration so it will be available in the next.
You might want to investigate Python's groupby function which helps with this kind of analysis.
from itertools import groupby
def num_diffs(seq):
return len(list(groupby(seq))) - 1
for test in ["TATA__", "TTAA__"]:
print(test, num_diffs(test))
This would display:
TATA__ 4
TTAA__ 2
The groupby() function works by grouping identical entries together. It returns a key and a group, the key being the matching single entry, and the group being a list of the matching entries. So each time it returns, it is telling you there is a difference.
Trying to make as little modifications to your original code as possible:
def num_diffs(state):
count = 0
for char2 in range(1, len(state)):
if state[char2 - 1] != state[char2]:
count += 1
return count
One of the problems with your original code was that the char2 variable was not initialized within the body of the function, so it was impossible to predict the function's behaviour.
However, working with indices is not the most Pythonic way and it is error prone (see comments for a mistake that I made). You may want rewrite the function in such a way that it does one loop over a pair of strings, a pair of characters at a time:
def num_diffs(state):
count = 0
for char1, char2 in zip(state[:-1], state[1:]):
if char1 != char2:
count += 1
return count
Finally, that very logic can be written much more succinctly — see #Ilja's answer.

Error:string index out of range, defining a function

I'm practicing coding on codingbat.com since I'm a complete beginner in python, and here is one of the exercises:
Given a string, return a new string made of every other char starting with the first, so "Hello" yields "Hlo".
Here is my attempt at defining the function string_bits(str):
def string_bits(str):
char = 0
first = str[char]
for char in range(len(str)):
char += 2
every_other = str[char]
return (first + every_other)
Running the code gives an error. What's wrong with my code?
A different approach, with an explanation:
If you need to handle a sentence, where spaces would be included, you can do this using slicing. On a string slicing works as:
[start_of_string:end_of_string:jump_this_many_char_in_string]
So, you want to jump only every second letter, so you do:
[::2]
The first two are empty, because you just want to step every second character.
So, you can do this in one line, like this:
>>> " ".join(i[::2] for i in "Hello World".split())
'Hlo Wrd'
What just happened above, is we take our string, use split to make it a list. The split by default will split on a space, so we will have:
["Hello", "World"]
Then, what we will do from there, is using a comprehension, iterate through each item of the list, which will give us a word at a time, and from there we will perform the desired string manipulation per i[::2].
The comprehension is: (documentation)
i[::2] for i in "Hello World".split()
Finally, we call "".join (doc), which will now change our list back to a string, to finally give us the output:
"Hlo Wrd"
Check out the slicing section from the docs: https://docs.python.org/3/tutorial/introduction.html
The problem is that the char += 2 returns a value greater than len(str) as len(str)-1 (the range) + 2 is longer than the string. You could do:
def string_bits(string):
if len(string) == 2:
return string[0]
result = ''
for char in range(0,len(string),2):#range created value sin increments of two
result += string[char]
return result
A more succinct method would be:
def string_bits(string):
return string[::2]
You should avoid using 'str' as a variable name as it is a reserved word by Python.
Ok, for me:
You should not use str as a variable name as it is a python built-in function (replace str by my_str for example)
For example, 'Hello' length is 5, so 0 <= index <= 4. Here you are trying to access index 3+2=5 (when char = 3) in your for loop.
You can achieve what you want with the following code:
def string_bits(my_str):
result = ""
for char in range(0, len(my_str), 2):
result += my_str[char]
return result
The error you are getting means that you are trying to get the nth letter of a string that has less than n characters.
As another suggestion, strings are Sequence-types in Python, which means they have a lot of built-in functionalities for doing exactly what you're trying to do here. See Built-in Types - Python for more information, but know that sequence types support slicing - that is, selection of elements from the sequence.
So, you could slice your string like this:
def string_bits(input_string):
return input_string[::2]
Meaning "take my input_string from the start (:) to the end (:) and select every second (2) element"

How to delete the very last character from every string in a list of strings

I have the strings '80010', '80030', '80050' in a list, as in
test = ['80010','80030','80050']
How can I delete the very last character (in this case the very last digit of each string which is a 0), so that I can end up with another list containing only the first four digits/characters from each string? So end up with something like
newtest = ['8001', '8003', '8005']
I am very new to Python but I have tried with if-else statements, appending, using indexing [:-1], etc. but nothing seems to work unless I end up deleting all my other zeros. Thank you so much!
test = ["80010","80030","80050"]
newtest = [x[:-1] for x in test]
New test will contain the result ["8001","8003","8005"].
[x[:-1] for x in test] creates a new list (using list comprehension) by looping over each item in test and putting a modified version into newtest. The x[:-1] means to take everything in the string value x up to but not including the last element.
You are not so far off. Using the slice notation [:-1] is the right approach. Just combine it with a list comprehension:
>>> test = ['80010','80030','80050']
>>> [x[:-1] for x in test]
['8001', '8003', '8005']
somestring[:-1] gives you everything from the character at position 0 (inclusive) to the last character (exclusive).
Just to show a slightly different solution than comprehension, Given that other answers already explained slicing, I just go through at the method.
With the map function.
test = ['80010','80030','80050']
print map(lambda x: x[:-1],test)
# ['8001', '8003', '8005']
For more information about this solution, please read the brief explanation I did in another similar question.
Convert a list into a sequence of string triples
In python #Matthew solution is perfect. But if indeed you are a beginer in coding in general, I must recommend this, less elegant for sure but the only way in many other scenario :
#variables declaration
test = ['80010','80030','80050']
length = len(test) # for reading and writing sakes, len(A): length of A
newtest = [None] * length # newtest = [none, none, none], go look up empty array creation
strLen = 0 # temporary storage
#adding in newtest every element of test but spliced
for i in range(0, lenght): # for loop
str = test[i] # get n th element of test
strLen = len (str) # for reading sake, the lenght of string that will be spliced
newtest[i] = str[0:strLen - 1] # n th element of newtest is the spliced n th element from test
#show the results
print (newtest) # ['8001','8003','8005']
ps : this scripts, albeit not being the best, works in python ! Good luck to any programmer newcommer.
I had a similar problem and here is the solution.
List<String> timeInDays = new ArrayList<>();
timeInDays.add(2d);
timeInDays.add(3d);
timeInDays.add(4d);
I need to remove last letter in every string in-order to compare them. Below solution worked for me.
List<String> trimmedList = new ArrayList<>;
for(int i=0;i<timeInDays.size();i++)
{
String trimmedString = timeInDays.get(i).substring(0,name.length()-1);
trimmedList=add(trimmedString );
}
System.out.println("List after trimming every string is "+trimmedList);

Can't convert len (x) into a usable int for string slicing?

I'm trying to write a function that takes a string and prints it normally, and then in reverse, like so:
string = "hello"
mirror(string)
'helloolleh'
This is the code i have so far:
def mirror(x) :
sentence = " "
length = len(x)
lengthstring = str(len(x))
lengthint = int(lengthstring)
sentence = x[lengthint, 0]
print x + sentence
but it keeps saying that len (x) is a tuple and not an int and it can't be part of the string slice?
The error I get with your code is:
File "<stdin>", line 6, in mirror
TypeError: string indices must be integers, not tuple
which says nothing about len(x). In fact, it is referring to the line
sentence = x[lengthint, 0]
in which you are trying to index x using lengthint, 0. Python assumes that your use of the comma indicates you want to index x using the tuple (lengthint, 0), which is not valid.
It seems that you are trying to use string slice syntax to reverse the string. String slice syntax uses :, not ,, like this:
sentence = x[lengthint:0]
But, since lengthint is greater than or equal to zero, that will never produce anything other than an empty result. You need to also tell Python to index backwards, like this:
sentence = x[lengthint:0:-1]
This almost works. It omits the first character of your original string in the reversed copy, because 0 indicates the position past the end position. So you have to use the special value None:
sentence = x[lengthint:None:-1]
After you do that and verify that it works, you can remove the use of lengthstring and lengthint (which I presume were added in an attempt to avoid the original error):
sentence = x[len(x):None:-1]
Finally, Python lets you omit the first two slice parameters in this case, leaving just:
sentence = x[::-1]
If your goal is to make this function work I think your approach is far too complicated. You can simple add the string to its reverse:
>>> def mirror(example):
... return example + example[::-1]
...
>>> mirror('hello')
'helloolleh'
Python supports stride-indexing, meaning that the [::-1] simply reverses the string.
you need to use ':' instead of ',' to slice string, for example
> value = '1234'
> print value[0:2]
12
In order to reverse the string you can just do x[::-1], thus, you can write mirror as below
def mirror(x):
return x + x[::-1]
Refer to https://docs.python.org/2.3/whatsnew/section-slices.html for details about slicing.

Categories