Reverse exercise (Python Codecademy course, part "Practice makes perfect" 15/15) - string

the task runs as follows:
Define a function called reverse that takes a string textand returns that string in reverse.You may not use reversed or [::-1] to help you with this.
My code works all right but I want to understand one detail. Tks to all.
def reverse (text):
result = ''
for i in range (len(text)-1,-1,-1):
result += text[i]
return result
The point is that originally I wrote in the 3rd line for i in range (len(text)-1,0,-1):But the program returned '!nohty' instead of '!nohtyP'. So I changed to (len(text)-1,-1,-1) ant it's ok.
BUT WHY?!

The end point is omitted from the range.
>>> range(2,5)
[2, 3, 4]
To get the zeroth element, you need -1.

Because the text (Python!) is of 7 length and lists are zero based (starting from 0) and the for loop is decreasing, you need to have -1.
The string "Python!" is 7 characters. Range is exclusive with the final number, thus the range is accounting for 6, 5, 4, 3, 2, 1, 0.
The length - 1 = 6, range of 6 to -1, where -1 is exclusive accounts for numbers 0 - 6. Because lists are 0 based, it accounts for all. With zero as the range's second argument, you only get the numbers 6, 5, 4, 3, 2, 1, which doesn't account for the whole word.
For example:
The word "Stack" has 5 letters.
Once it is a list, it occupies the indices 0, 1, 2, 3, 4.
You are looping through the whole word, thus you need to access the 0th element. To do that, the range must go to -1 exclusive.
For your loop:
>>> range(6, -1, -1)
[6, 5, 4, 3, 2, 1, 0]
Then, when you access it by doing:
text = "Python!"
for i in range(len(text)-1, -1, -1):
print(text[i])
text[i] accesses all the individual characters and prints them, backwards.

Related

Single slice getting elements from beginning and end of list in Python?

The first and last N elements of a list in Python can be gotten using:
N = 2
my_list = [0, 1, 2, 3, 4, 5]
print(my_list[:N] + my_list[-N:])
# [0, 1, 4, 5]
Is it possible to do this with a single slice in pure Python? I tried my_list[-N:N], which is empty, and my_list[N:-N], which gives exactly the elements I don't want.
For the builtin types, slices are by definition consecutive – a slice represents a start, end and step between them. There is no way for a single slice operation to represent non-consecutive elements, such as head and tail of a list.

Getting rid of duplicates from a pair of corresponding lists

This is a program that I recently made. The goal of this code is to a pair of corresponding lists. So randomStringpt1[0] corresponds to randomStringpt2[0]. I want to compare randomStringpt1[0] and randomString2[0] to the rest of the pairs that the user gave in the randomStrings. But after using this code, it looks like I have duplicated each pair many times, which is the opposite of what I was looking for. I was thinking of using a dictionary, but then realized that a dictionary key could only have one value, which wouldn't help my case if the user used a number twice. Does anyone know how I can reduce the duplicates?
(The tests I have been running have been with the numbers randomStringpt1 = [1,3,1,1,3] and randomStringpy2 = [2,4,2,3,4]
)
randomStringpt1 = [1, 2, 3, 4, 5] #Pair of strings that correspond to each other("1,2,3,4,5" doesn't actually matter)
randomStringpt2 = [1, 2, 3, 4, 5]
for i in range(len(randomStringpt1)):
randomStringpt1[i] = input("Values for the first string: ")
randomStringpt2[i] = input("Corresponding value for the second string: ")
print(randomStringpt1) #numbers that the user chose for the first number of the pair
print(randomStringpt2) #numbers that the user chose for the second number of the pair
newStart = []
newEnd = []
for num1 in range(len(randomStringpt1)):
for num2 in range(len(randomStringpt1)):
if (int(randomStringpt1[num1]) != int(randomStringpt1[num2]) and int(randomStringpt2[num1]) != int(randomStringpt2[num2])):
newStart.append(randomStringpt1[num1]) # Adding the pairs that aren't equal to each other to a new list
newEnd.append(randomStringpt2[num1])
newStart.append(randomStringpt1[num2])
newEnd.append(randomStringpt2[num2])
# else:
# print("The set of numbers from the randomStrings of num1 are not equal to the ones in num2")
print(newStart)
print(newEnd)
First let's analyze the 2 bugs in your code,
the if condition inside the loop is true every time a pair compares to a different one. this means for your example it should output
[1, 1, 3, 3, 3, 1, 1, 1, 1, 3, 3, 3]
[2, 2, 4, 4, 4, 2, 2, 3, 3, 4, 4, 4]
since you compare every pair to any other pair that exists. But your output is different because you append both pairs every time and getting a very big result, so you shouldn't append the num2 pairs.
Now, from what you described that you want, you should loop every pair and check if it already exists in the output list. So the for loop part can change like this
filtered = []
for pair in zip(randomStringpt1,randomStringpt2):
if pair not in filtered:
filtered.append(pair) # Adding the pairs that aren't equal to each other to a new list
the zip function takes the 2 lists and for every loop it returns 2 values one from each list the first value pair, then the second values and goes on. the filtered list will be in the following format [(1, 2), (3, 4), (1, 3)]
Alternative it can be as a one liner like this:
filtered = list(dict.fromkeys(zip(randomStringpt1, randomStringpt2)))
using the dictionary to identify unique elements and then turn it back into a list
after all that you can get the original format of the lists you had in your code by splitting them like this
newStart = [pair[0] for pair in filtered]
newEnd = [pair[1] for pair in filtered]
Finally i should tell you to read a little more on python and it's for loops, since the range(len(yourlist)) is not the python intended way to loop over lists, as python for loops are equivalent to for each loops on other languages and iterate over the list for you instead on relying in a value to get list elements like yourlist[value].

create list from list where values only increase by 1

I have the code below that gets the maximum value from a list. It then compares it to the maximum value of the remaining values in the list, and if it is more than 1 higher than the next greatest value, it replaces the original list maximum with 1 higher than the next greatest value. I would like the code to search the entire list and make sure that any value in the list is at most 1 larger than any other value in the list. I know this ins’t the best worded explanation, I hope the example lists below make what I’m trying to accomplish clearer.
for example I don’t want to get a final list like:
[0,2,0,3]
I would want the final list to be
[0,1,0,2]
input:
empt=[0,2,0,0]
Code:
nwEmpt=[i for i in empt if i !=max(empt)]
nwEmpt2=[]
for i in range(0,len(empt)):
if (empt[i]==max(empt))&(max(empt)>(max(nwEmpt)+1)):
nwEmpt2.append((max(nwEmpt)+1))
elif (empt[i]==max(empt))&(max(empt)==(max(nwEmpt)+1)):
nwEmpt2.append(max(empt))
else:
nwEmpt2.append(empt[i])
output:
nwEmpt2
[0,1,0,0]
min_value = min(empt)
empt_set = set(empt)
for i in empt:
nwEmpt.append(min_value + len(list(filter(lambda x: x < i, empt_set))))
This gives e.g. for input empt = [8, 10, 6, 4, 4] output nwEmpt = [6, 7, 5, 4, 4].
It works by mapping each element to (the minimum value) + (the number of distinct values smaller than element).

Python range - Print from desired number till desired number

Python range () seems to be weird. I want to print the number from 1 to 9, for that I have typed the following code
for i in range(1,10):
print i
Is there a way of mentioning the start and end numbers in range(). Should I use any other function that can do this for me. Any help would be appreciated.
You are making an assumption that range(1,10) means that
10 is for printing 10th number starting from 0.
in the comments. This isn't how range() works.
range() takes three arguments, 2 required and 1 optional:
range(start, stop, step). (further reading)
start should be the number you want to start with
stop is the number you want to stop before
step is the increment range you would like to walk between start and stop
For instance range(1,10) will contain all the numbers from 1-9 (note: not including 10): [1, 2, 3, 4, 5, 6, 7, 8, 9]
range(0,10) would include 0 to above, while range(1,11) would include 10.
range(1,10,2) would render [1, 3, 5, 7, 9]
As for your desire for a "cleaner" solution; that is a subjective question. A list comprehension like [i for i in range(1,10)], or even your nested code in the question is pretty clean by most people's standards.

How to find how many items are in the same position in two lists?python

I need to be able to check if any items in one list are also in another list but in the same position. I have seen others but they return true or false. I need to know how many are in the same position.
So compare them directly!
This of course is assuming both lists are the same length:
a = [1, 1, 2, 3, 4, 5, 7, 8, 9]
b = [1, 2, 3, 4, 5, 6, 7, 8, 9]
matches = 0
for index in range(len(a)):
if a[index] == b[index]:
matches += 1
print mat
Try it here!
overlap = set(enumerate(listA)).intersection(set(enumerate(listB))
print(len(overlap))
enumerate pairs up elements with their index, so you can check how many common element/ index pairs exist between the two lists.
One advantage of this approach (as opposed to iterating through either list yourself) is that it automatically takes care of the case where the lists have different lengths.
demo

Resources