Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Multi-level HashMaps

Status
Not open for further replies.

Kirsle

Programmer
Jan 21, 2006
1,179
0
0
US
I'm developing a program that needs to read data in from text files and store them in a hierarchical data structure. Here is example input and the data structure in the way Perl would parse it:

(this is for chatting robots. + is what the human says, - is how the bot replies (can have more than one - for random responses), and * are conditionals)

Code:
> topic testing
   + hello bot
   - Hello human.
   - Hi.

   + my name is *
   * <get name> == <star> => I know, you've told me before.
   - <set name=<star>>Nice to meet you!
   - <set name=<star>>I'll remember your name.
< topic

$VAR1 = {
   topics => {
      testing => {
         "hello bot" => {
            reply => {
               0 => "Hello human.",
               1 => "Hi.",
            }
         },
         "my name is *" => {
            reply => {
               0 => "<set name=<star>>Nice to meet you.",
               1 => "<set name=<star>>I'll remember your name.",
            },
            condition => {
               0 => "<get name> == <star> => I know, you've told me your name already.",
            },
         },
      },
   },
};

In Perl, building this data structure is easy, as is getting data back from it. For instance

Code:
$data->{topics}->{testing}->{'hello bot'}->{reply}->{1} = "Hi.";

So when porting this to Java, I decided to use HashMaps that would contain more HashMaps. Here's parts of my Java code:

Code:
private HashMap topics = new HashMap(); // Main reply structure

...

private boolean parse(String[] code) {
   // Track some temporary variables.
   String topic    = "random"; // Default topic=random
   int lineno      = 0;        // Track line numbers
   boolean comment = false;    // In a multi-line comment
   boolean inobj   = false;    // Trying to parse an object
   String objname  = "";       // Name of the current object
   Vector objbuf   = null;     // Object code buffer
   String ontrig   = "";       // Current trigger we're parsing
   int repcnt      = 0;        // Reply counter
   int concnt      = 0;        // Condition counter
   String lastcmd  = "";       // Last command code
   String isThat   = "";       // Is a %Previous trigger.
...

else if (cmd.equals("+")) {
   // + TRIGGER
   say("\tTrigger pattern: " + line);
   if (isThat.length() > 0) {
      // TODO
   }
   else {
      // Initialize the sub-hashmaps.
      [COLOR=red]HashMap trigspace  = new HashMap();
      HashMap replyspace = new HashMap();
      HashMap condspace  = new HashMap();
      trigspace.put("reply",replyspace);
      trigspace.put("condition",condspace);[/color]

      // Do any triggers exist for this topic yet?
      if (topics.containsKey(topic) == false) {
         say("\tInitializing topic space for topic: " + topic);
         HashMap topicspace = new HashMap();
         topics.put(topic, topicspace);
      }

      // Add the (empty) trigger space to it.
      say("\tInitializing trigger space for pattern: " + line);
      [COLOR=red]HashMap topicspace = (HashMap) topics.get(topic);
      topicspace.put(line, trigspace);
      topics.put(topic, topicspace);[/color]
   }

   // Init some temp vars for the following commands.
   ontrig = line;
   repcnt = 0;
   concnt = 0;
}

...

else if (cmd.equals("-")) {
   // - REPLY
   if (ontrig.equals("")) {
      cry("Response found before trigger!");
      continue;
   }

   say("\tResponse: " + line);

   if (isThat.length() > 0) {
      // TODO
   }
   else {
      [COLOR=red]// Fetch the trigger space.
      HashMap topicspace = (HashMap) topics.get(topic);
      HashMap trigspace  = (HashMap) topicspace.get(ontrig);
      HashMap replyspace = (HashMap) trigspace.get("reply");

      // Add this reply.
      replyspace.put(repcnt, line);

      // Rebuild the hashmaps.
      trigspace.put("reply", replyspace);
      topicspace.put(ontrig, trigspace);
      topics.put(topic, topicspace);[/color]
   }

   repcnt++;
}

Is there a more efficient way of handling the data structure than what I'm doing here?

Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
I doubt your requirement can be solved by using multiple binary trees.
 
It seems to be solvable so far... just with a lot of extra work. The whole parsing function is mostly finished and I wrote one that dumps everything back out in a way that looks like Perl's Data::Dumper (so I could visually see the data structure).

Is there a better way to do it then?

Cuvou.com | My personal homepage
Code:
perl -e '$|=$i=1;print" oo\n<|>\n_|_";x:sleep$|;print"\b",$i++%2?"/":"_";goto x;'
 
>Is there a better way to do it then?
You might seriously consider using VoiceXML in the long run and its related speech interface frameworks. That would be at least take out part of the portability barrier. But, I am not in a position to give any detail.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top