Checking for Palindromes in APL, Python and other Programming Languages

Sam GutsellAPLLeave a Comment

Recently we had a special date on the calendar, that some of you may have noticed. The date in question is February 2nd 2020, which when written in any of these formats: DD/MM/YYYY (UK), MM/DD/YYYY (US) or YYYYMMDD (ISO), is in fact a palindrome (excluding ‘/’ or other symbols). This made me think about how I could check for palindromes using APL.

What is a palindrome?

When approaching this problem, the first question is what is the definition of a palindrome? A palindrome is something that can be read the same backwards as it is forwards, for example: racecar, 1001, was it a rat I saw? (excluding symbols and spaces) and the reason I’m writing about palindromes, 02/02/2020.


Fun fact

The last time we saw a date that is palindromic in UK, US and ISO formats, before 02/02/2020 was 909 years ago, 11/11/1111. We now won’t see another one for 101 years, 12/12/2121.


Investigating the problem in APL

Input format

I have decided that the input should be in ISO format; this means February 2nd 2020 in this format would be 20200202 which is YYYYMMDD. So, with this and the definition of a palindrome in mind, I know my first task, reverse the input of the function. Luckily, in APL, we have a symbol which will reverse anything that you pass it, the symbol is called Circle Stile and when called with only a right argument performs reverse. For example: ⌽'rats' returns 'star'.

Checking the input against the reversed input

Now we have the normal input and the reversed input we need to compare the two. We can compare them using the symbol Equals Underbar which performs a match operation on two items. For example: 'rats'≡'rats' returns 1 which means true, because they match, and 'rats'≡'star' returns 0 which means false, because they don’t match.

Let’s say the input is called num if we write an expression to evaluate if the input is the same forward as it is backwards we can write it like this: num≡⌽num, however this will only work if the variable num is a text string.

User interaction

When we come to write a function to solve the issue we will need to incorporate user input. We can use Quad and Quote Quad to ask the user for a number and retrieve that number as text. ⎕←'Enter any number: ' will output to the user saying 'Enter any number: ', the user would then type in their response and we can capture that using which captures their input as text.

Putting it all together

We then need to evaluate their input to check to see if they have entered a palindromic number. To achieve this, we can use the expression I already detailed previously num≡⌽num. However, there is another way of writing this same expression using a function train, (⌽≡⊢). You would use this expression like this: (⌽≡⊢)num, which when broken down simply means (⌽num)≡(⊢num). This is because we apply the left and right symbols in the bracket to num the left hand one I’ve detailed above and the right hand one, Right Tack , means use the right argument, and in this case, we only have a right argument. We then say result of left symbol (match) result of right symbol, therefore this is reversed num match num.


My solution for checking for palindromes in APL

In APL we have a couple of ways of defining a function, traditional functions and direct functions, my solution can be implemented as either one of these.

As a Traditional function:


∇r←palindrome_trad;num
⎕←'Enter any number: '
num←⍞
:If (⌽≡⊢)num
     r←'Given number is a palindromic number'
:Else
     r←'Given number is not a palindromic number'
:EndIf
∇

As a Direct function:


Palindrome_dfn←{
     ⎕←'Enter any number: '
     num←⍞
     (⌽≡⊢)num:'Given number is a palindromic number'
     'Given number is not a palindromic number'
 }


The solutions in other languages

After solving the problem for myself in APL I was curious to see how the same thing could be achieved in other languages. I decided to search the web for solutions in C, Java and Python.

Checking for palindromes in C

This is how to check whether a given number is a palindrome in C:
I found the C Solution here.


#include 

int main() {
    int n, n1, rev = 0, rem;
    
    printf("Enter any number: ");
    scanf("%d", &n);    
    n1 = n;
    
    /* logic */    while (n > 0){
        rem = n % 10;
        rev = rev * 10 + rem;
        n = n / 10;
    }
    
    if (n1 == rev){
        printf("Given number is a palindromic number"); 
    }
    else{
        printf("Given number is not a palindromic number"); 
    }    
    return 0; 
}


Checking for palindromes in Java

This is how to check whether a given number is a palindrome in Java:
I found the Java Solution here, I amended this slightly from the source material to match the input request and function output.


import java.util.Scanner;
public class Example24  {

    public static void main(String args[])
    {
	 Scanner in = new Scanner(System.in);
     System.out.print("Enter any number: ");
     int n = in.nextInt();
     int sum = 0, r;
	 int temp = n;    
     while(n>0)
	   {    
        r = n % 10;   
        sum = (sum*10)+r;    
        n = n/10;    
       }    
      if(temp==sum)    
        System.out.println("Given number is a palindromic number");    
      else    
        System.out.println("Given number is not a palindromic number");    
     }  
}


Checking for palindromes in Python

This is how to check whether a given number is a palindrome in Python: I found the Python Solution here (I amended this slightly from the source material to match the input request and function output).


n=int(input("Enter any number: "))
temp=n
rev=0
while(n>0):
    dig=n%10
    rev=rev*10+dig
    n=n//10
if(temp==rev):
    print("Given number is a palindromic number")
else:
    print("Given number is not a palindromic number")

After seeing the other solutions, I can only see two real similarities between my solution and the others: the way we retrieve the input and the control structure at the end to return the result. A similarity between the other solutions is that they are all using the same mathematical approach. When I coded my solution I wasn’t aware of this mathematical approach, so I used a couple of built in operations instead: using to retrieve text from the user without the user having to specify the number as a string and using to reverse the input to make the comparison easier.


Implementing this mathmatical approach in APL

I wanted to see how those solutions were operating so I decided to translate the mathematical approach into an APL solution too (based mainly on the python solution shown above).


palindrome;dig;rev;temp;n
⎕←'Enter any number: '
n←⎕
temp←n
rev←0
:While n>0
     dig←10|n
     rev←dig+rev×10
     n←⌊n÷10
:EndWhile

:If temp=rev
     ⎕←'Given number is a palindromic number'
:Else
     ⎕←'Given number is not palindromic number'
:EndIf



Anymore?

I’d love to see if any readers can come up with other solutions (perhaps even in other languages). If you send them to info@optima-systems.co.uk we will post them below this articles (or use the comments section below).



Responses


Peter Merritt, Senior APL Consultant at Optima Systems

Taken from comments section below.

Thanks Sam. How about this for generating a list of all palindrome dates (0-9999 AD):


r←PalindromeDates;dd;mm;xx;yy;zz;mmdd;dates
⍝ return a list of possible dates in CCYYMMDD format which could be palindromes
dd←{↓'ZI2'⎕FMT⍳⍵}¨31 29 31 30 31 30 31 31 30 31 30 31
⍝ get formatted vector of days in months
mm←↓'ZI2'⎕FMT⍳12
⍝ get a formatted vector of months in year
yy←∪,↑(⊂mm){,⍺∘.,⍵}¨dd
⍝ append each to each for unique list of legit month:days pairs
mmdd←(∊{~0∊⍴⍵~' '}¨yy)/yy
⍝ remove empty elements
dates←(⌽¨mmdd),¨mmdd
⍝ reverse each month/day set to form year, prefix to month/day pairs
r←dates[⎕AV⍋(↑dates)]
⍝ sort into ascending date order

⍝ TO DO:
⍝ - remove non-legitimate leap years
⍝ - extend beyond year 9999



James Heslip, APL Team Leader at Optima Systems

Taken from comments section below.

Great article Sam. The APL solution you post works great for text input:


(⌽≡⊢)'101'
1

But for numeric input it falls short and (incorrectly) says everything is a palindrome:


(⌽≡⊢)123
1

You've avoided this issue in this article with the use of Quote Quad converting the data type to text, and then checking it. If you want to avoid the conversion, you can use the following in APL:


(⌽≡⊢)10⊥⍣¯1⊢123
0

(⌽≡⊢)10⊥⍣¯1⊢101
1

Essentially we're using a change of base to split the number from a scalar out into individual digits:


10⊥⍣¯1⊢123
1 2 3

This is equivalent to (but using scalar extension in our favour):


10 10 10⊤123
1 2 3

When we have a vector, we can then rotate it and compare correctly. The rotation of a scalar is the scalar itself, hence why the initial method doesn't work for numerics.



Adám Brudzewsky, Computer Programmer at Dyalog Ltd

Taken from comments section below.

How about going branchless?


Palindrome_branchless←{
  ⎕←'Enter any number:'
  num←⍞
  yes←'Given number is a palindromic number'
  no←'Given number is not a palindromic number'
  ⊃no yes⌽⍨(⌽≡⊢)num
}


About the Author

Sam Gutsell

APL Developer


Sam is an APL Developer at Optima Systems. He started at Optima in 2012 as an apprentice straight after finishing College. Sam decided to take Computing whilst studying at college, yet, he never intended to but, he thought it sounded interesting at the time. Sam’s original career plans involved studying Meteorology at university, to become a Meteorologist. His plans changed when he realised how much he enjoyed code. More about Sam.


More from Sam



Other Posts