Tuesday, July 15, 2014

Check for palindrome

In the Input and Output chapter of A Byte of Python, the code of a simple palindrome checker is presented. As homework exercise, we are required to improve it, so that it would accept as a palindrome something like "Rise to vote, sir." (courtesy of The Simpsons). That is, we have to skip punctuation and spaces, and not to care about case.

The main part of the code I have written gets a string as raw data from input, than is going to call a palindrome() function that returns True only when a palindrome is detected:
txt = raw_input('your input: ')
print 'This is',
if not palindrome(txt):
    print 'not',
print 'a palindrome'
Not much to say about it, I guess.

Following the Swaroop's suggestion to use a tuple to store the ignored characters and strip them from the original string in input, I wrote the palindrome() function in this way:
def palindrome(text):
    text = strip(text) # 1
    return text == text[::-1] # 2
1. A strip() function removes all the uninteresting characters from the original input.
2. I compare the stripped user input with its reverted representation, and return True only if they match. The string reverting is adequately commented by Swaroop. In brief, I create a copy of the original text by slicing, but saying that I want the entire interval to be considered. The third parameter says that I want to step negatively, and this result in reading the string form right to left.

And finally, here is how I have written my stripping function:
def strip(text):
    ignore = (',', '.', ' ') # 1

    stripped = '' # 2
    for c in text: # 3
        if c not in ignore: # 4
            stripped += c

    return stripped
1. This is the suggested ignore tuple. Actually, I put in it just three characters. Question mark, colon, semicolon, are just a few of the many candidates to enter in this selection.
2. The resulting string is initially empty.
3. Loop on all the characters in input.
4. If the current character is not in the ignore tuple I can add it to the output string.

This is it. Homework done. Still, the above #1 line it is quite painful. Can't we get rid of this manual initialization?

If we can relax a bit the original requirements, we could end up with a sleeker piece of code.
Say that is alright if we can happily get rid of any non-alphanumeric character. In this case we can use a very simple regular expression, and simplify the palindrome() function in this way:
import re # 1


def palindrome(text):
    text = re.sub(r'\W+', '', text) # 2
    return text == reverse(text)
1. I am using the python regular expression library.
2. I ask to re to substitute each non-alphanumeric subsequence in the original text with an empty one.

If you don't want to be so aggressive, you could write your own specific regular expression and strip just the characters you need to.

Sunday, January 12, 2014

Ternary operator example

If you come to Python from a C (or related language as C++ and Java) experience, you have probably developed a taste for the ternary conditional operator (?:). However, Guido van Rossum didn't like it, and it wasn't part of the original language. Luckily for us, in the end he changed his mind, and since version 2.5 it is available a new construct that we can happily use to get this effect. See PEP 308 - Conditional Expressions for details. It goes in this way:
first if test else second
And it reads: check test, if it is true returns first, otherwise second. I found it sort of perlish, but I guess in a while I should get used to it. I reckoned it was sort of fun showing how to use it by a simple programming problem. Say that you have a file containing a bunch of integers, each one on a different line, do not worry about any error handling. You have to write a python script that read that file and output for each number in input a 0 for any odd number and 1 for the even ones. Here is how I solved it:
import sys

data = open(sys.argv[1], 'r')
for line in data:
    print(1 if int(line) % 2 == 0 else 0)
As comparison, In C++ I would have written the same piece of code like this:
int value;
while(file >> value)
    std::cout << (value % 2 == 0 ? 1 : 0) << std::endl;

Saturday, January 4, 2014

Fibonacci for CodeEval

Just to have some fun, I was solving a not too complex problem on CodeEval. The description was sort of dodgy, but in the end I understood that it boiled down to calculate the Fibonacci number of the values passed as input (increased by one, to make the waters a bit muddier). I usually play those games in C++, that is my preferred programming language. Alas, on CodeEval we are forced to use a 32 bit C++98 compiler. Not exactly what you could call a state of the art tool. This is particularly annoying in this case, where I need to calculate huge numbers as the Fibonacci ones are. Luckily my basic knowledge of Python is enough to get me out of it. Here is my 2.7 solution, I know it is nothing special, but it sufficed to get me a shiny 100%:
import sys


def fib(n):
    if n == 0:
       return 0

    prev, cur = 0, 1
    for i in range(n - 1):
        prev, cur = cur, prev + cur
    return cur


if __name__ == '__main__':
    for line in open(sys.argv[1]):
        if len(line) > 0:
            print fib(int(line) + 1)