How does this python palindrome function work? - python

can someone explain this function to me?
#from the geeksforgeeks website
def isPalimdrome(str):
for i in range(0, int(len(str)/2)):
if str[i] != str[len(str)-i-1]:
return False
return True
I dont understand the for loop and the if statement.
A - why is the range from 0 to length of the string divided by 2?
B - what does "str[len(str)-i-1" do?
//sorry, ik I ask stupid questions

To determine if a string is a palindrome, we can split the string in half and compare each letter of each half.
Consider the example
string ABCCBA
the range in the for loop sets this up by only iterating over the first n/2 characters. int(n/2) is used to force an integer (question A)
ex_str = 'ABCCBA'
for s in range(int(len(ex_str)/2)):
print(ex_str[s])
A
B
C
we now have to look at the letters in the other half, CBA, in reverse order
adding an index to our example to visualize this
string ABCCBA
index 012345
to determine if string is a palindrome, we can compare indices 0 to 5, 1 to 4, and 2 to 3
len(str)-i-1 gives us the correct index of the other half for each i (question B)
example:
ex_str = 'ABCCBA'
for s in range(int(len(ex_str)/2)):
print(f'compare index {s} to index {len(ex_str)-s-1}')
print(f"{ex_str[s]} to {ex_str[len(ex_str) - s - 1]}")
compare index 0 to index 5
A to A
compare index 1 to index 4
B to B
compare index 2 to index 3
C to C

for i in range(0, int(len(str)/2)):
Iterate through(go one by one from) 0(because in string first letter's index is 0) to half length of the string.
Why to only half length?
Because in a palindrome you need to compare only half length of string to the other half.
e.g., RADAR. 0=R, 1=A, 2=D, 3=A, 4=R. Number of letters = 5.
int(len(str)/2) will evaluate to 2. So first two letters will be compared with last two letters and middle one is common so will not be compared.
if str[i] != str[len(str)-i-1]:
Now, length of string is 5 but index of letters in string goes from 0 to 4, which is why len(str)-1 (5-1 = 4, i.e., last letter R).
len(str)-1-i Since i is a loop variable, it will be incremented by 1 every time for loop runs. In first run i is 0, in second 1....
The for loop will run two times.
str[i] != str[len(str)-1-i] will be evaluated as-
0 != 4 i.e. R != R FALSE
1 != 3 i.e. A != A FALSE
This code is not very readable and can be simplified as pointed out by others. This also reflects why code readability is important.

1. why is the range from 0 to length of the string divided by 2?
That's because we don't need to iterate all the way through the string but just halfway through it.
2. what does "str[len(str)-i-1]" do?
It returns the ith element from the end ie for a string "noon" when i is 0 it will get str[3] ie n

Easiest way to check palindrome is this
def isPalimdrome(s):
return s == s[::-1]
Reading the string from the beginning is same as reading it reverse.

Related

Function that returns the length of the longest run of repetition in a given list

I'm trying to write a function that returns the length of the longest run of repetition in a given list
Here is my code:
def longest_repetition(a):
longest = 0
j = 0
run2 = 0
while j <= len(a)-1:
for i in a:
run = a.count(a[j] == i)
if run == 1:
run2 += 1
if run2 > longest:
longest = run2
j += 1
run2 = 0
return longest
print(longest_repetition([4,1,2,4,7,9,4]))
print(longest_repetition([5,3,5,6,9,4,4,4,4]))
3
0
The first test function works fine, but the second test function is not counting at all and I'm not sure why. Any insight is much appreciated
Just noticed that the question I was given and the expected results are not consistent. So what I'm basically trying to do is find the most repeated element in a list and the output would be the number of times it is repeated. That said, the output for the second test function should be 4 because the element '4' is repeated four times (elements are not required to be in one run as implied in my original question)
First of all, let's check if you were consistent with your question (function that returns the length of the longest run of repetition):
e.g.:
a = [4,1,2,4,7,9,4]
b = [5,3,5,6,9,4,4,4,4]
(assuming, you are only checking single position, e.g. c = [1,2,3,1,2,3] could have one repetition of sequence 1,2,3 - i am assuming that is not your goal)
So:
for a, there is no repetitions of same value, therefore length equals 0
for b, you have one, quadruple repetition of 4, therefore length equals 4
First, your max_amount_of_repetitions=0 and current_repetitions_run=0' So, what you need to do to detect repetition is simply check if value of n-1'th and n'th element is same. If so, you increment current_repetitions_run', else, you reset current_repetitions_run=0.
Last step is check if your current run is longest of all:
max_amount_of_repetitions= max(max_amount_of_repetitions, current_repetitions_run)
to surely get both n-1 and n within your list range, I'd simply start iteration from second element. That way, n-1 is first element.
for n in range(1,len(a)):
if a[n-1] == a[n]:
print("I am sure, you can figure out the rest")
you can use hash to calculate the frequency of the element and then get the max of frequencies.
using functional approach
from collections import Counter
def longest_repitition(array):
return max(Counter(array).values())
other way, without using Counter
def longest_repitition(array):
freq = {}
for val in array:
if val not in freq:
freq[val] = 0
freq[val] += 1
values = freq.values()
return max(values)

Using range, len, and % to print string

I'm a newbie to Python and one of our practice examples is in the code below but there is no feedback on what the code is doing. The question in the exercise asks "How many times is P printed out" I've provided the output below.
From what I understand on my own, the length of s is 6 and the range is 0 to 5 but since we are saying "range(len(s))" are we basically asking the loop to run 6 times?
Also, can someone help me understand the print(s[idx % 2])? How does the print statement generate the output shown below? If I were to change it to print(s[ 0:2 ] then I would be given "pypypy" horizontally which is different.
Thank you for the help.
s = "python"
for idx in range(len(s)):
print(s[idx % 2])
Output
p
y
p
y
p
y
Strings in Python are arrays of bytes representing unicode characters. However, Python does not have a character data type, a single character is simply a string with a length of 1. Square brackets can be used to access elements of the string. Therefore you can get the character at position 1 (remember that the first character has the position 0) via the following code snippet, e.g:
a = "Hello, World!"
print(a[1]) // e
print(a[2]) // l
Now looking at why your code outputs what it does (second part of your question). Recall that % is the modulo operator.
In the first run, idx = 0. So your statement becomes:
print(s[0 % 2]) = print(s[0]) = 'p' -> first letter of s.
Next idx = 1. So your statement becomes:
print(s[1 % 2]) = print(s[1]) = 'y' -> second letter of s.
Next idx = 2. So your statement becomes:
print(s[2 % 2]) = print(s[0]) = 'p' -> first letter of s.
And so on, 6 times (idx takes values of 0, 1, 2, 3, 4, 5).
P.S. Commenting on your comment regarding setting print(s[ 0:2 ]) - this is known as string slicing (essentially call out a range of characters from the string) - [0:2] means you are starting at index 0 and extend up to but not including index 2, so 'py'.
are we basically asking the loop to run 6 times?
Yes
can someone help me understand the print(s[idx % 2])?
Yes
How does the print statement generate the output shown below?
The % operator is the modulo operator. It gives the remainder of a division. For the range in question, the results are
0 divided by 2 is 0 with a remainder of 0
1 divided by 2 is 0 with a remainder of 1
2 divided by 2 is 1 with a remainder of 0
3 divided by 2 is 1 with a remainder of 1
4 divided by 2 is 2 with a remainder of 0
5 divided by 2 is 2 with a remainder of 1
As you can see, the remainder toggles between 0 and 1.
Indexing the string will thus result in s[0] which is p and s[1] which is y.

IndexError: list index out of range in codewars puzzle

As a beginner in Python I decided to have a go at the Codewars puzzles.
Codewars uses Python 2.7.6.
The second puzzle requires you to:
Write a function that will return the count of distinct case-insensitive alphabetic characters and numeric digits that occur more than once in the input string. The input string can be assumed to contain only alphabets (both uppercase and lowercase) and numeric digits.
For example, if you give the program "abcde" it should give you 0, because there are no duplicates. But, if you give it "indivisibilities" it should give you 2, because there are 2 duplicate letters: i (occurs 7 times) and s (occurs twice).
As a beginner I came up with an approach that I imagine is very crude, but nevertheless it works perfectly on my system:
def duplicate_count(text):
# the number of duplicates
dupes = 0
# convert input string to lower case and split into individual characters
list_of_chars = list(text.lower())
# sort list into groups
sorted_chars = sorted(list_of_chars)
# get length of list
n = len(sorted_chars)
# check whether the first element of the list is the same as the second. If
# it is, add one to the dupes count
if sorted_chars[0] == sorted_chars[1]:
dupes += 1
else:
dupes += 0
# start with the second element (index: 1) and finish with the (n - 1)-th
# element
for i in range(1, n - 1):
# if the ith element of the list is the same as the next one, add one
# to the dupes count. However, since we only want to count each
# duplicate once, we must check that the ith element is not the same as
# the previous one
if sorted_chars[i] == sorted_chars[i + 1] and sorted_chars[i] != sorted_chars[i - 1]:
dupes += 1
else:
dupes += 0
return dupes
This passes all of the automated tests, but when I submit this as a solution I get an STDERR:
Traceback:
in <module>
in duplicate_count
IndexError: list index out of range
As I understand it, this error is given if I try and access an element of the list that does not exist. But I cannot see where in my code I am doing that. I calculate the length of my list and store it in n. So let's say I supply the string "ababa" to duplicate_count, it should generate a list sorted_chars: ['a', 'a', 'a', 'b', 'b'] of length 5. So n = 5. Therefore range(1, n - 1) = range(1, 4) which will generate the numbers 1, 2 and 3. Thus for i in range(1, n - 1) is, mathematically speaking, for each i ϵ I = {1, 2, 3}. The largest index I therefore use in this code is 4 (if sorted_chars[i] == sorted_chars[i + 1]), which is fine, because there is an element at index 4 (in this case 'b').
Why, then, is Codewars giving me this error.
In this case, your function requires at least two characters to work. Try running duplicate_count('a') and see the error it throws. Add the following after n = len(sorted_chars):
if n < 2:
return 0
That will stop running the rest of the function and return 0 duplicates (because you can't have any if there's only one character).

Python: Does list contain 3 consecutive integers that sum to 7?

I am working through the prep materials for my application to a coding bootcamp. This is a practice problem I am struggling with (using Python):
"Write a function 'lucky_sevens(numbers)', which takes in a list of integers and print True if any three consecutive elements sum to 7.
Make sure your code correctly checks for the first and last elements of the array."
I know how to loop through an array one element at a time, but don't know how to "hold" one element while also assessing the second and third elements in relation to the first, as this prompt requires. As you can see from my attempt below, I'm not sure when/where/how to increment the index values to search the whole list.
def lucky_sevens(numbers):
index1 = 0 # For assessing 1st of 3 numbers
index2 = index1 + 1 # For assessing 2nd of 3 numbers
index3 = index2 + 1 # For assessing 3rd of 3 numbers
# If all index values are within the list...
if index1 <= (len(numbers) - 2) and index2 <= (len(numbers) - 1) and index3 <= len(numbers):
# If the values at those indices sum to 7...
if numbers[index1] + numbers[index2] + numbers[index3] == 7:
print True
else:
print False
# I think the increments below may be one of the places I am incorrect
index1 += 1
index2 += 1
index3 += 1
When I run
lucky_sevens([2, 1, 5, 1, 0])
It is printing False, I think because it is only considering elements in the 0th, 1st and 2nd positions (sums to 8, not 7, as required).
It should print True, because elements in the 1st, 2nd and 3rd positions sum to 7. (1 + 5 + 1 = 7).
Can anyone please provide a suggestion? I would be most appreciative.
Yes, for your case its only considering the first, second and third elements. This is because you do not have any loops in your function.
In Python loop constructs are for and while . So you would need to use either one.
I can give you some hints to the problem , not going to provide you the complete code (since otherwise how would you learn?) -
You need to loop through the indexes from first index (0) to the len(numbers) -2 . An easy function that can help you do this would be enumerate() , it spits out the index as well as actual element when iterating over it using for loop (If you are using enumerate , you would need to put a condition to check that index should be less than len(numbers) - 2).
You should then get the elements from index+1 pos and index+2 position as well, and sum them and check if thats equal to 7 , if so you should return True.
A common mistake many make is to return False if the above (2) condition is not met, but actually what you need to do is to return it only when there are no matches at all (at the end of the function) .
You need a loop through the list to evaluate all elements. In your code, you only evaluate the first 3 elements.
Try this:
def lucky_sevens(numbers):
for i in range(0, len(numbers)):
if sum(numbers[i:i + 3]) == 7:
print True
return
print False
The reason yours doesn't work is because you're not looping it, you only check the first 3 elements in the list.
What about using recursion?
def lucky_sevens(numbers, index=0):
if index <= len(numbers):
if sum(numbers[index:index + 4]) == 7:
return True
else:
index += 1
return lucky_sevens(numbers[1:], index)
return False

Finding common letters between 2 strings in Python

For a homework assignment, I have to take 2 user inputted strings, and figure out how many letters are common (in the same position of both strings), as well as find common letters.. For example for the two strings 'cat' and 'rat', there are 2 common letter positions (which are positions 2 and 3 in this case), and the common letters are also 2 because 'a' is found one and 't' is found once too..
So I made a program and it worked fine, but then my teacher updated the homework with more examples, specifically examples with repetitive letters, and my program isn't working for that.. For example, with strings 'ahahaha' and 'huhu' - there are 0 common letters in same positions, but there's 3 common letters between them (because 'h' in string 2 appears in string 1, three times..)
My whole issue is that I can't figure out how to count if "h" appears multiple times in the first string, as well as I don't know how to NOT check the SECOND 'h' in huhu because it should only count unique letters, so the overall common letter count should be 2..
This is my current code:
S1 = input("Enter a string: ")
S2 = input("Enter a string: ")
i = 0
big_string = 0
short_string = 0
same_letter = 0
common_letters = 0
if len(S1) > len(S2):
big_string = len(S1)
short_string = len(S2)
elif len(S1) < len(S2):
big_string = len(S2)
short_string = len(S1)
elif len(S1) == len(S2):
big_string = short_string = len(S1)
while i < short_string:
if (S1[i] == S2[i]) and (S1[i] in S2):
same_letter += 1
common_letters += 1
elif (S1[i] == S2[i]):
same_letter += 1
elif (S1[i] in S2):
common_letters += 1
i += 1
print("Number of positions with the same letter: ", same_letter)
print("Number of letters from S1 that are also in S2: ", common_letters)
So this code worked for strings without common letters, but when I try to use it with "ahahaha" and "huhu" I get 0 common positions (which makes sense) and 2 common letters (when it should be 3).. I figured it might work if I tried to add the following:
while x < short_string:
if S1[i] in S2[x]:
common_letters += 1
else:
pass
x += 1
However this doesn't work either...
I am not asking for a direct answer or piece of code to do this, because I want to do it on my own, but I just need a couple of hints or ideas how to do this..
Note: I can't use any functions we haven't taken in class, and in class we've only done basic loops and strings..
You need a data structure like multidict. To my knowledge, the most similar data structure in standard library is Counter from collections.
For simple frequency counting:
>>> from collections import Counter
>>> strings = ['cat', 'rat']
>>> counters = [Counter(s) for s in strings]
>>> sum((counters[0] & counters[1]).values())
2
With index counting:
>>> counters = [Counter(zip(s, range(len(s)))) for s in strings]
>>> sum(counters[0] & counters[1].values())
2
For your examples ahahaha and huhu, you should get 2 and 0, respectively since we get two h but in wrong positions.
Since you can't use advanced constructs, you just need to simulate counter with arrays.
Create 26 elements arrays
Loop over strings and update relevant index for each letter
Loop again over arrays simultaneously and sum the minimums of respective indexes.
A shorter version is this:
def gen1(listItem):
returnValue = []
for character in listItem:
if character not in returnValue and character != " ":
returnValue.append(character)
return returnValue
st = "first string"
r1 = gen1(st)
st2 = "second string"
r2 = gen1(st2)
if len(st)> len(st2):
print list(set(r1).intersection(r2))
else:
print list(set(r2).intersection(r1))
Note:
This is a pretty old post but since its got new activity,I posted my version.
Since you can't use arrays or lists,
Maybe try to add every common character to a var_string then test
if c not in var_string:
before incrementing your common counter so you are not counting the same character multiple times.
You are only getting '2' because you're only going to look at 4 total characters out of ahahaha (because huhu, the shortest string, is only 4 characters long). Change your while loop to go over big_string instead, and then add (len(S2) > i) and to your two conditional tests; the last test performs an in, so it won't cause a problem with index length.
NB: All of the above implicitly assumes that len(S1) >= len(S2); that should be easy enough to ensure, using a conditional and an assignment, and it would simplify other parts of your code to do so. You can replace the first block entirely with something like:
if (len(S2) > len(S1)): (S2, S1) = (S1, S2)
big_string = len(S1)
short_string = len(S2)
We can solve this by using one for loop inside of another as follows
int y=0;
for(i=0;i<big_string ;i++)
{
for(j=0;j<d;j++)
{
if(s1[i]==s2[j])
{y++;}
}
If you enter 'ahahaha' and 'huhu' this code take first character of big
string 'a' when it goes into first foor loop. when it enters into second for loop
it takes first letter of small string 'h' and compares them as they are not
equal y is not incremented. In next step it comes out of second for loop but
stays in first for loop so it consider first character of big string 'a' and
compares it against second letter of small string 'u' as 'j' is incremented even
in this case both of them are not equal and y remains zero. Y is incremented in
the following cases:-
when it compares second letter of big string 'h' and small letter of first string y is incremented for once i,e y=1;
when it compares fourth letter of big string 'h' and small letter of first string y is incremented again i,e y=2;
when it compares sixth letter of big string 'h' and small letter of first string y is incremented again i,e y=3;
Final output is 3. I think that is what we want.

Categories