Search code examples
listhashtcl

Need Sorted Tcl Output


I have a file called file1.txt whose contents are as described below

Contents for file1.txt:

AND 60
NAND 20
OR 30

SUN 90
SIN 10
SIM 80

EW 25
NEW 85
PHEW 55

So, total the file has 9 lines with two empty lines , data contains 2 columns and 3 rows in every group and there are 3 such groups with two empty lines between them. Write a Tcl code to read file1.txt is possible use Hashes to sort these 3 groups and print 3 groups in ascending order. as shown below Output:

NAND 20
OR 30
AND 60

SIN 10
SIM 80
SUN 90

EW 25
PHEW 55
NEW 85

When you write the code make it elastic and scalable to data input containing hundreds of such groups and don't limit it for only 3 groups containing 3 entries

I already tried below code and this does not give correct output

# Function to read the file and organize data into a hash
proc readAndOrganizeDataFromFile {filename} {
    set fileId [open $filename]
    set data [read $fileId]
    close $fileId

    set groups [split $data "\n\n"]
    set hashTable [dict create]

    foreach group $groups {
        set lines [split $group "\n"]
        foreach line $lines {
            if {$line eq ""} {
                continue ;# Skip empty lines
            }

            set parts [split $line]
            set key [lindex $parts 0]
            set value [lindex $parts 1]

            dict lappend hashTable $key $value
        }
    }

    return $hashTable
}

# Function to sort and print the hash table
proc sortAndPrintHash {hashTable} {
    set sortedKeys [lsort -dictionary [dict keys $hashTable]]

    foreach key $sortedKeys {
        set values [dict get $hashTable $key]
        set output [join $values " "]
        puts $output
    }
}

# Example usage
set filename "file1.txt"
set hashTable [readAndOrganizeDataFromFile $filename]
sortAndPrintHash $hashTable

Solution

  • There are several problems:

    1. You are using the split command incorrectly:
      split string ?splitChars?
         Returns a list created by splitting string at each character that is in
         the splitChars argument. 
    

    When splitChars is set as "\n\n" it means to split the string by every "\n"...not by two \n characters in a row. splitChars is a set of individual characters, not an exact string.

    1. You're not preserving the original data by the original groups.
      All the data is going into one big flat dict. There's no way to report it back by groups again.

    2. You're sorting the data by key, not value.

    My suggestion is to read the orginal file as a dict where key is the group number and the value is a list of lists. Then sort each value of the dict with lsort -index 1 in order to sort each value by the second element in each list.

    proc readAndOrganizeDataFromFile {filename} {
        set fileId [open $filename]
        set data [read $fileId]
        close $fileId
    
        set hashTable [dict create]
    
        set lines [split $data "\n"]
        set group_num 0
        foreach line $lines {
            if {$line eq ""} {
                incr group_num
                continue
            }
    
            # key = group_num
            # value = list of lines
            dict lappend hashTable $group_num $line
        }
    
        return $hashTable
    }
    
    proc sortAndPrintHash {hashTable} {
        set sortedKeys [lsort -dictionary [dict keys $hashTable]]
    
        foreach key $sortedKeys {
            set values [dict get $hashTable $key]
            set sorted_value [lsort -dictionary -index 1 $values]
    
            foreach value $sorted_value {
                puts $value
            }
    
            puts ""
        }
    }
    
    # Example usage
    set filename file1.txt
    set hashTable [readAndOrganizeDataFromFile $filename]
    sortAndPrintHash $hashTable