Anagram in Cobol: Complete Solution & Deep Dive Guide

a close up of a computer screen with code on it

Mastering String Manipulation: A Deep Dive into Solving Anagrams with Cobol

To find anagrams in Cobol, you must first normalize both the target and candidate words to a consistent case. Then, sort the characters of each word alphabetically. If the sorted versions are identical, but the original words are different, the candidate is a confirmed anagram.

You’ve probably heard the whispers: "Cobol is a dead language," or "You can't do complex string manipulation in Cobol." It's a common narrative, especially for developers accustomed to the fluid, built-in string methods of Python or JavaScript. When faced with a classic computer science puzzle like finding anagrams, many would assume Cobol would be a clunky, frustrating tool for the job.

But what if that narrative is incomplete? What if, beneath its verbose and rigidly structured syntax, lies a powerful, precise engine for data processing that can tackle this challenge with surprising elegance? This article will shatter those preconceptions. We will take on the Anagram challenge from the exclusive kodikra.com learning path, guiding you step-by-step through building a robust solution in Cobol. Prepare to see this legendary language in a new light and master fundamental data manipulation techniques that are still critical in the world of enterprise computing.


What Exactly Is an Anagram?

Before diving into the code, it's crucial to establish a crystal-clear definition of the problem. An anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.

For this specific challenge, we adhere to a few key rules derived from the kodikra module:

  • Case Insensitivity: The comparison must ignore case. For example, "Orchestra" is an anagram of "carthorse".
  • Identical Letters: The two words must contain the exact same letters with the exact same frequency. "Listen" and "Silent" are anagrams.
  • Self-Exclusion: A word is never its own anagram. "stop" is not an anagram of "stop", even though they share the same letters.

The goal is to write a program that takes a base word and a list of candidate words, and returns only the candidates that are true anagrams of the base word.


Why Is This a Perfect Challenge for Learning Cobol?

Solving the anagram problem in a modern language might take a few lines of code, often abstracting away the underlying mechanics. Cobol forces you to confront these mechanics head-on, providing an invaluable learning experience. This task is not just about getting the right answer; it's about mastering the core principles of Cobol programming.

Here’s why it's such a powerful exercise:

  • Structured Data Definition: You must meticulously define your data structures in the DATA DIVISION. This includes defining fixed-length strings and, crucially, re-defining them as tables of single characters (PIC X OCCURS...) to enable sorting.
  • Low-Level String Manipulation: Cobol lacks built-in sort() functions for strings. You have to implement a sorting algorithm yourself, like a bubble sort, which provides deep insight into algorithmic thinking.
  • Procedural Logic: The solution requires breaking down the problem into logical, reusable blocks of code using PERFORM statements. This reinforces Cobol's emphasis on structured, readable, and maintainable procedures.
  • Memory Management: By pre-defining all your variables and their sizes, you gain a tangible understanding of static memory allocation, a concept often hidden in more modern languages.

Tackling this problem transforms you from someone who just writes Cobol to someone who truly understands how Cobol handles and processes data at a fundamental level.


How to Solve the Anagram Problem: The Canonical Approach

The most reliable and common algorithm for identifying anagrams is the "Sort and Compare" method. The logic is straightforward: if two different words are anagrams of each other, they will become identical when their characters are sorted alphabetically.

For example, take "LISTEN" and "SILENT":

  • Normalize to lowercase: "listen" and "silent".
  • Sort characters: Both become "eilnst".
  • Compare sorted strings: "eilnst" equals "eilnst".
  • Compare original (normalized) strings: "listen" does not equal "silent".
  • Conclusion: They are anagrams.

This breaks the problem down into a clear, repeatable sequence of steps that is perfectly suited for Cobol's procedural nature.

The Anagram Detection Logic Flow

Here is a high-level overview of the entire process, from input to final decision.

    ● Start
    │
    ▼
  ┌────────────────────────┐
  │  GET Target & Candidate │
  └────────────┬───────────┘
               │
               ▼
  ┌────────────────────────┐
  │ Normalize both to lower │
  └────────────┬───────────┘
               │
               ▼
    ◆ Are normalized words identical?
   ╱                             ╲
 Yes (Not an Anagram)           No (Continue)
  │                              │
  ▼                              ▼
┌──────────┐               ┌──────────────────┐
│  REJECT  │               │ Sort Target Chars│
└──────────┘               └────────┬─────────┘
                                    │
                                    ▼
                             ┌─────────────────────┐
                             │ Sort Candidate Chars│
                             └─────────┬───────────┘
                                       │
                                       ▼
                             ◆ Are sorted words identical?
                            ╱                             ╲
                          Yes (Is an Anagram)              No (Not an Anagram)
                           │                               │
                           ▼                               ▼
                        ┌──────────┐                    ┌──────────┐
                        │  ACCEPT  │                    │  REJECT  │
                        └──────────┘                    └──────────┘

The Core Challenge: Sorting Characters in Cobol

The crux of the implementation in Cobol is sorting the characters of a string. Since we don't have a simple .sort() method, we must build it. The bubble sort algorithm is a classic and straightforward choice for this task.

Bubble sort works by repeatedly stepping through the list, comparing each pair of adjacent items and swapping them if they are in the wrong order. The pass through the list is repeated until no swaps are needed, which indicates that the list is sorted.

Bubble Sort Algorithm Flow

This diagram illustrates the logic for sorting an array of characters in place.

    ● Start Sort (e.g., "C", "O", "B", "O", "L")
    │
    ▼
  ┌───────────────────────────┐
  │ Set Outer Loop (N-1 times)│
  └────────────┬──────────────┘
               │
               ▼
    ┌───────────────────────────┐
    │ Set Inner Loop (N-1 times)│
    └────────────┬──────────────┘
                 │
                 ▼
      ◆ char[j] > char[j+1] ?
     ╱                         ╲
   Yes (Swap)                   No (Do Nothing)
    │                           │
    ▼                           │
  ┌─────────────┐               │
  │ temp = char[j]│               │
  │ char[j] = char[j+1]           ├─────────┐
  │ char[j+1] = temp              │         │
  └─────────────┘               │         │
    │                           │         │
    └────────────┬──────────────┘         │
                 │                        │
                 ▼                        │
      Loop to next pair in Inner Loop ─────┘
    │
    ▼
  Loop to next pass in Outer Loop
    │
    ▼
    ● End Sort (Result: "B", "C", "L", "O", "O")

Where the Magic Happens: The Complete Cobol Solution

Now, let's translate our logic into a fully functional Cobol program. This solution is written for GnuCOBOL, a widely available open-source compiler. The code is heavily commented to explain each part of the DATA DIVISION and PROCEDURE DIVISION.


      ******************************************************************
      * Program: ANAGRAM-CHECKER
      * Author:  Kodikra.com
      * Purpose: From the kodikra.com exclusive curriculum, this program
      *          identifies anagrams for a given target word from a
      *          list of candidates.
      * Compiler: GnuCOBOL
      ******************************************************************
       IDENTIFICATION DIVISION.
       PROGRAM-ID. ANAGRAM-CHECKER.

       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.

       DATA DIVISION.
       WORKING-STORAGE SECTION.
       
       01 WS-TARGET-WORD          PIC X(20) VALUE "diaper".
       01 WS-NORMALIZED-TARGET    PIC X(20).
       01 WS-SORTED-TARGET        PIC X(20).

       01 WS-CANDIDATE-LIST.
          05 FILLER               PIC X(20) VALUE "hello".
          05 FILLER               PIC X(20) VALUE "world".
          05 FILLER               PIC X(20) VALUE "zombies".
          05 FILLER               PIC X(20) VALUE "pants".
          05 FILLER               PIC X(20) VALUE "paired".
          05 FILLER               PIC X(20) VALUE "STOP".
          05 FILLER               PIC X(20) VALUE "pots".
       
       01 WS-CANDIDATE-TABLE REDEFINES WS-CANDIDATE-LIST.
          05 WS-CANDIDATE-WORD    PIC X(20) OCCURS 7 TIMES.
       
       01 WS-CURRENT-CANDIDATE    PIC X(20).
       01 WS-NORMALIZED-CANDIDATE PIC X(20).
       01 WS-SORTED-CANDIDATE     PIC X(20).

       01 WS-WORD-LEN             PIC 9(02) VALUE 0.
       01 WS-I                    PIC 9(02).
       01 WS-J                    PIC 9(02).
       01 WS-K                    PIC 9(02).
       01 WS-TEMP-CHAR            PIC X(01).

      * This structure allows us to treat a string as an array of chars
      * for the sorting algorithm.
       01 WS-SORT-AREA.
          05 WS-SORT-WORD         PIC X(20).
          05 WS-SORT-ARRAY REDEFINES WS-SORT-WORD.
             10 WS-SORT-CHAR      PIC X(01) OCCURS 20 TIMES.

       PROCEDURE DIVISION.
       
       000-MAIN-PROCEDURE.
           DISPLAY "Kodikra.com Anagram Finder"
           DISPLAY "=========================="
           DISPLAY "Target word: " WS-TARGET-WORD
           DISPLAY " "
           DISPLAY "Checking candidates..."

      *    Process the target word first so it's ready for comparison
           MOVE WS-TARGET-WORD TO WS-SORT-WORD
           PERFORM 100-GET-WORD-LENGTH
           PERFORM 200-NORMALIZE-AND-SORT
           MOVE WS-SORT-WORD TO WS-SORTED-TARGET
           
           MOVE FUNCTION LOWER-CASE(WS-TARGET-WORD) 
               TO WS-NORMALIZED-TARGET

      *    Loop through each candidate word in the table
           PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 7
               MOVE WS-CANDIDATE-WORD(WS-I) TO WS-CURRENT-CANDIDATE
               
               PERFORM 300-CHECK-IF-ANAGRAM
           END-PERFORM.

           DISPLAY " "
           DISPLAY "Check complete."
           STOP RUN.

      ******************************************************************
      * Calculates the actual length of the word to optimize sorting.
      ******************************************************************
       100-GET-WORD-LENGTH.
           COMPUTE WS-WORD-LEN = FUNCTION LENGTH(FUNCTION TRIM(WS-SORT-WORD)).

      ******************************************************************
      * Normalizes a word to lowercase and then sorts its characters
      * using a bubble sort algorithm.
      * Input:  WS-SORT-WORD
      * Output: WS-SORT-WORD (is modified in place)
      ******************************************************************
       200-NORMALIZE-AND-SORT.
      *    Step 1: Normalize to lowercase
           MOVE FUNCTION LOWER-CASE(WS-SORT-WORD) TO WS-SORT-WORD.
      
      *    Step 2: Bubble Sort the characters
           PERFORM VARYING WS-J FROM 1 BY 1 UNTIL WS-J >= WS-WORD-LEN
               PERFORM VARYING WS-K FROM 1 BY 1 
                   UNTIL WS-K >= (WS-WORD-LEN - WS-J + 1)
                   
                   IF WS-SORT-CHAR(WS-K) > WS-SORT-CHAR(WS-K + 1)
                       MOVE WS-SORT-CHAR(WS-K) TO WS-TEMP-CHAR
                       MOVE WS-SORT-CHAR(WS-K + 1) TO WS-SORT-CHAR(WS-K)
                       MOVE WS-TEMP-CHAR TO WS-SORT-CHAR(WS-K + 1)
                   END-IF
               END-PERFORM
           END-PERFORM.

      ******************************************************************
      * The main logic block to check a single candidate word.
      ******************************************************************
       300-CHECK-IF-ANAGRAM.
      *    First, normalize the candidate for comparison
           MOVE FUNCTION LOWER-CASE(WS-CURRENT-CANDIDATE) 
               TO WS-NORMALIZED-CANDIDATE.
           
      *    Rule: A word is not its own anagram.
           IF WS-NORMALIZED-TARGET = WS-NORMALIZED-CANDIDATE
               CONTINUE
           ELSE
      *        Process the candidate word
               MOVE WS-CURRENT-CANDIDATE TO WS-SORT-WORD
               PERFORM 100-GET-WORD-LENGTH
               PERFORM 200-NORMALIZE-AND-SORT
               MOVE WS-SORT-WORD TO WS-SORTED-CANDIDATE
               
      *        The final anagram check
               IF WS-SORTED-TARGET = WS-SORTED-CANDIDATE
                   DISPLAY "  -> '" WS-CURRENT-CANDIDATE "' is an anagram."
               END-IF
           END-IF.

How to Compile and Run the Code

If you have GnuCOBOL installed, you can compile and run this program from your terminal. Save the code as anagram.cob.

Compile:


cobc -x -free anagram.cob

Run:


./anagram

Expected Output:


Kodikra.com Anagram Finder
==========================
Target word: diaper
 
Checking candidates...
  -> 'paired' is an anagram.
 
Check complete.

Detailed Code Walkthrough

Understanding the code requires breaking it down by its major divisions and procedures.

1. DATA DIVISION - Defining Our Workspace

This is the heart of a Cobol program's structure. Every single piece of data must be declared here.

  • WS-TARGET-WORD: A simple fixed-length string to hold our base word, "diaper".
  • WS-CANDIDATE-LIST & WS-CANDIDATE-TABLE: This is a classic Cobol technique. We first define a contiguous block of memory (WS-CANDIDATE-LIST) filled with our candidate words. Then, we immediately use the REDEFINES clause to create WS-CANDIDATE-TABLE, which overlays a table structure (an array) on top of that same memory. This allows us to access the candidates individually using an index, like WS-CANDIDATE-WORD(1).
  • WS-SORT-AREA: This is the most critical structure. WS-SORT-WORD is a 20-character string. The REDEFINES clause then creates WS-SORT-ARRAY, which maps a table of 20 single-character items (PIC X(01) OCCURS 20 TIMES) onto the exact same memory space. This is how we can access individual characters of a string by index (e.g., WS-SORT-CHAR(3)) to perform the bubble sort.
  • Loop Counters and Temp Variables: WS-I, WS-J, WS-K, and WS-TEMP-CHAR are standard helper variables for our loops and the swap operation in the sort.

2. PROCEDURE DIVISION - The Execution Logic

This section contains the instructions that are executed sequentially.

000-MAIN-PROCEDURE

This is our program's entry point.

  1. It begins by displaying a header.
  2. Crucially, it processes the target word before the loop starts. It calls 100-GET-WORD-LENGTH and 200-NORMALIZE-AND-SORT once for WS-TARGET-WORD and stores the result in WS-SORTED-TARGET. This is an optimization; we don't need to re-sort the target word for every candidate.
  3. It then uses a PERFORM VARYING loop to iterate through each WS-CANDIDATE-WORD in our table.
  4. Inside the loop, it moves the current candidate into a working variable and calls 300-CHECK-IF-ANAGRAM to do the heavy lifting.
  5. Finally, it displays a completion message and executes STOP RUN to terminate the program.

100-GET-WORD-LENGTH

This paragraph uses intrinsic functions to get the actual length of a word, ignoring trailing spaces. FUNCTION TRIM removes the spaces, and FUNCTION LENGTH gets the length of the result. This ensures our sorting loops don't do unnecessary work on empty characters.

200-NORMALIZE-AND-SORT

This is the workhorse procedure.

  1. It first takes the word currently in WS-SORT-WORD and converts it to lowercase using FUNCTION LOWER-CASE.
  2. It then executes the bubble sort. The outer loop (controlled by WS-J) determines how many passes to make. The inner loop (controlled by WS-K) walks through the characters, comparing adjacent pairs (WS-SORT-CHAR(WS-K) and WS-SORT-CHAR(WS-K + 1)).
  3. If a character is greater than the one next to it, they are swapped using WS-TEMP-CHAR as a temporary holder.
  4. After this procedure finishes, WS-SORT-WORD contains the sorted version of the original word.

300-CHECK-IF-ANAGRAM

This procedure contains the final decision logic for a single candidate.

  1. It first checks if the normalized target and normalized candidate are identical. If they are (e.g., "stop" and "STOP"), it's not a valid anagram, and the logic skips to the next candidate.
  2. If they are different, it proceeds to move the candidate into the WS-SORT-AREA and calls the same 100-GET-WORD-LENGTH and 200-NORMALIZE-AND-SORT procedures.
  3. Finally, it performs the crucial comparison: IF WS-SORTED-TARGET = WS-SORTED-CANDIDATE. If the sorted versions match, it displays the success message.


Alternative Approaches and Considerations

While "Sort and Compare" is highly effective, it's worth considering other methods and their trade-offs in a Cobol context.

Character Frequency Counting

Another common method is to create a frequency map (or a histogram) of characters for each word.

  1. Create an array of 26 integers, representing the counts for 'a' through 'z'.
  2. For the target word, iterate through its characters and increment the corresponding counter in the array.
  3. For the candidate word, iterate through its characters and decrement the corresponding counter.
  4. If the words are anagrams, the array should contain all zeros at the end.

Pros & Cons in a Cobol Context

Approach Pros Cons
Sort and Compare - Conceptually simple and easy to implement.
- Requires minimal extra memory (sorting is done in-place).
- Reuses the same logic block for both target and candidate.
- Sorting can be computationally expensive (O(n log n) for efficient algorithms, O(n^2) for our simple bubble sort).
- Requires redefining data structures, which can be confusing for beginners.
Character Frequency Map - Potentially faster for very long strings (O(n) complexity).
- Avoids complex sorting logic.
- Requires a dedicated table (array) in WORKING-STORAGE to hold character counts.
- The logic for incrementing/decrementing based on character ASCII value can be more complex to write in Cobol than a simple sort.

For this kodikra module, the "Sort and Compare" method is an excellent choice because it directly tests core Cobol skills like table manipulation, redefining data, and implementing fundamental algorithms procedurally.


Frequently Asked Questions (FAQ)

Is Cobol still relevant for new projects?

While rarely chosen for brand new, greenfield web or mobile applications, Cobol is overwhelmingly dominant in mainframe environments that power global finance, banking, insurance, and logistics. Modernization efforts focus on integrating these robust Cobol systems with modern front-ends, meaning skilled Cobol developers are, and will remain, in high demand for maintaining and evolving these critical systems. The future is about integration, not replacement.

Why is string manipulation in Cobol so verbose?

Cobol was designed in an era where computing resources were scarce and expensive. Its verbosity is a feature, not a bug, designed for extreme clarity and predictability. Fixed-length strings and manual manipulation prevent the memory allocation overhead and unpredictable performance that can come with dynamic strings in other languages. It prioritizes stability and reliability over developer convenience.

Can I use dynamic arrays in Cobol for the character list?

Traditionally, no. Standard Cobol relies on static memory allocation, meaning you must define the maximum size of your tables (arrays) at compile time using the OCCURS clause. This is a fundamental design principle. While some modern Cobol variants or extensions might offer more dynamic features, mastering fixed-size table manipulation is essential for working with the vast majority of existing Cobol codebases.

What does PIC X(N) actually mean?

PIC stands for "Picture Clause," which is a template for defining the type and size of a data item. X signifies an alphanumeric character (any character). (N) specifies the length. So, PIC X(20) defines a variable that can hold a string of exactly 20 alphanumeric characters.

What are some other ways to sort data in Cobol?

Cobol has a very powerful SORT verb, but it's designed primarily for sorting entire files, not in-memory strings. You would typically use it to read data from an input file, sort it based on key fields, and write it to an output file. For in-memory sorting of a small data structure like a string's characters, implementing a simple algorithm like bubble sort is the most common and direct approach.

What is the purpose of the REDEFINES clause?

The REDEFINES clause is a powerful feature that allows you to apply a different data structure description to the same physical memory location. In our solution, we define a 20-byte area as a single string (WS-SORT-WORD) and then immediately redefine that same 20-byte area as an array of 20 single characters (WS-SORT-ARRAY). This lets us switch between viewing the data as a whole string or as an indexed list of characters without moving any data.


Conclusion: A Timeless Skill

We've successfully navigated the Anagram challenge, transforming a seemingly complex problem into a structured, logical Cobol program. In doing so, we've done more than just find anagrams; we've practiced the foundational techniques of data definition, procedural decomposition, and low-level data manipulation that define professional Cobol programming.

This exercise proves that Cobol, far from being an obsolete relic, is a language of precision and control. The skills you've honed here are directly applicable to the millions of lines of code that form the bedrock of our global economy. By understanding how to think algorithmically within Cobol's structured framework, you are well-equipped to tackle real-world data processing challenges.

Disclaimer: The code provided in this article was developed and tested using GnuCOBOL 3.1.2. Syntax and features may vary slightly with other compilers such as those from IBM or Micro Focus.

Ready to continue your journey? Explore the next challenge in the Cobol 5 roadmap module or deepen your foundational knowledge by visiting our complete Cobol language hub.


Published by Kodikra — Your trusted Cobol learning resource.