views:

132

answers:

5

I have a list of student names and their id. Sometimes I need to search name using id, sometimes I need to search id using name.

  • If using array[id] = name, then it is quick to find a name using an id but slow to find the id using a name.
  • If using hash{name} = id, then it is quick to find the id using a name but slow to find the name from an id.

What is the best data structure to represent student a name ↔ id relation? Note: the student name is a string while id is a sequential integer from 1 to the total number of these students.

Thanks.

+2  A: 

You could just combine both "fast" approaches. Use an array to lookup id -> name, and a hash to go from name -> id.

By "database," I assume you're just talking about some data structure (like an array or hash) and not a relational database (like MySQL).

Matt Ball
A: 

One way could be to use both of these implementations. Use array when you need name from id and use hash when you need id from name. Not sure if it's the best way though.

Raze2dust
A: 

Use both an array and a hash. Your question is a special case of this question.

In Perl, you can use the tie mechanism to make a class that looks like a hash with an additional method for look up by id, but where additions and deletions maintain both a hash and an array behind the scenes.

Tie::Hash::TwoWay provides a dual-lookup data structure with a hash both ways. It would probably be suitable for your purpose (there isn't much to be gained by storing student ids in an array except fast enumeration in student id order), and if not it can serve as inspiration.

Gilles
how can I make use of this functionsub hashValueAscendingNum { $student_record{$a} <=> $grades{$b};}which sort the hash{name}=id by value
ignore the above comment I added. see below:how can I make use of this function sub hashValueAscendingNum { $student_record{$a} <=> $student_record{$b}; } which sort the $student_record{name}=id by value id
@lilili08: you can delete or edit your comments, rather than just posting a new one.
Matt Ball
+4  A: 
swestrup
since the student list is long and eat memory,I do not want to create both hash and array. I just to make the student name consume memory for once.but look like $student_by_id and $student_by_name copy student name again.it is correct?
@lilili08 In programing you often have to choose between memory use and speed. If you must have both look ups fast you must use some memory to accomplish it.
Ven'Tatsu
No, lilili08, there is only one copy of the student information kept, in the @student array. The other two arrays do NOT carry copies of the information, but references to it. If you modify the record in $student[1], then $student_by_name{'Bob Brown'} and $student_by_id[2] will change as well. Read up about perl references with 'perldoc perlreftut'
swestrup
@swestrup I think you might want to assume that student IDs are sparse, and have student_by_id also be a hash.
hobbs
@hobbs: I normally would assume that, but the answer explicitly states that student ids are sequential integers from 1 to the number of students. Even if some elements (like 0) are missing, that's sufficiently un-sparse to justify an array. Always read the spec.
swestrup
In that case, you don't need `@student`; `@student_by_id` can easily do both jobs :)
hobbs
@hobbs: Oh, I considered that too, but I can easily imagine many scenarios in which the need to maintain student ids in some particular order could become onerous, so I assumed they were essentially random. This could happen if, for example, the student records were concatenated from several administrative files and then read in.
swestrup
+1  A: 

I often create hashes that contain a record of information and different index hashes to locate them.

my $record 
    = { name          => 'James'
      , rank          => 'Captain'
      , serial_number => '007'
      };

foreach my $field ( qw<name rank serial_number> ) { 
    my $ref = \$lookup{ $field }{ $record->{ $field } };
    if ( ref( $$ref ) eq 'ARRAY' || !$lookup{meta}{$field}{is_unique} ) { 
        push @$ref, $record;
    }
    else { 
        $$ref = $record;
    }
}

That's the guts, though I'd probably encapsulate the record and the lookup mechanism.

Axeman
what does this code mean? the student name list is long, I do not want to store it in memory using multiple data structure. just want to store it in memory once. does your implementation save memory? Thanks
@lilili08, it *is* only stored once, in two different hashes. It's a classic memory-time tradeoff.
Axeman