Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / June 2006

Tip: Looking for answers? Try searching our database.

hash of hashes

Thread view: 
Mani - 02 Jun 2006 19:45 GMT
if hash is used, i think in java it can be used as,

if the statement in perl is,

$names{$branch}=0;

equivalent to,

if (branch.length() > 0)  names.put(branch, new Integer(0));

In perl a "hash of hashes" is used as,

$names{$branch}{$account}=0;

i would like to know how it can be coded in java?

-Mani
Oliver Wong - 02 Jun 2006 20:00 GMT
> if hash is used, i think in java it can be used as,
>
[quoted text clipped - 11 lines]
>
> i would like to know how it can be coded in java?

Sounds like what perl calls "hash", Java calls Map. So to implement a "hash
or hashes", use a Map of Map. E.g.

Map<KEY_TYPE,Map<KEY_TYPE,VALUE_TYPE>> names = new
Map<KEY_TYPE,Map<KEY_TYPE,VALUE_TYPE>>();
names.get(branch).put(account, 0);

   - Oliver
dimitar - 04 Jun 2006 03:45 GMT
BTW, quite often Perl people use hash of hashes in places where they'd
be better served by real objects.

e.g. compare:

Map<String, Map<String, Integer>> branches = ....;
branches.get(branchId).get(accountId);

to:

class Branch {
   private String branchId;
   private String address;
   private Map<String, String> accounts;
   private Collection<Person> employees;

   public String getAccount(String accountId) {
       return accounts.get(accountId)
   }
}

Map<String, Branch> id2branch = ....;
id2branch.get(branchId).getAccount(accountId);
Stefan Ram - 04 Jun 2006 05:10 GMT
>> In perl a "hash of hashes" is used as,
>> $names{$branch}{$account}=0;
[quoted text clipped - 3 lines]
>Map<KEY_TYPE,Map<KEY_TYPE,VALUE_TYPE>>();
>names.get(branch).put(account, 0);

 Here "names.get(branch)" will return null. One needs to add
 code to create another map as the value of "get(branch)".

 In Perl, this is not neccessary.
 Perl has a feature called "autovivifications", that will
 assure that "$name{$branch}" exists and is a map. The script

use Data::Dumper;
$names{"branch"}{"account"} = 123;
print Data::Dumper::Dumper(%names), "\n";

 prints

$VAR1 = 'branch';
$VAR2 = {
         'account' => 123
       };

 It is not neccessary to build the map structure in Perl.
 The script essentially consists only of the single line
 »$names{"branch"}{"account"} = 123;«. The other two lines
 are there only to get the debug output. Possibly a slight
 variation makes this even clearer:

use Data::Dumper;
$names->{"branch"}->{"account"} = 123;
print Data::Dumper::Dumper($names), "\n";

 prints:

$VAR1 = {
         'branch' => {
                       'account' => 123
                     }
       };

 So both maps are "magically" created in Perl. One does not
 have to tell Perl that the reference $names is a reference to
 a map, which actually needs to be allocated and then have its
 address written into »$names«, before it can be assigned to.
 The single line »$names->{"branch"}->{"account"} = 123;« will
 suffice.

 Here is a simple example of autovivification in a special
 case for Java:

class NumericMapUtils
{ public static <D> void addTo
 ( final java.util.Map<D,java.lang.Integer> map, final D d, final int i )
 { map.put( d, i +( map.containsKey( d )? map.get( d ): 0 )); }}

 Now one can declare a map:

final java.util.Map<java.lang.Integer,java.lang.Integer> map =
new java.util.HashMap<java.lang.Integer,java.lang.Integer>();

 And then add 7 to its entry 4:

NumericMapUtils.<java.lang.Integer>addTo( map, 4, 7 );

 If the entry 4 does not exist yet, it will be created (hence,
 "autovivification") with an initial value of 0 by »addTo«.

 Perl is even smarter: By the usage »...{"account"} = 123;«
 it was able to figure out that here not "0" is needed as the
 initial value, but another map instead.

 Here is an excerpt from a knowledge base I wrote in Perl:

sub set($$$$$)
{ push @{ $::assertion }, [ ${$_[ 0 ]}, ${$_[ 1 ]}, ${$_[ 2 ]}, ${$_[ 3 ]}, $_[ 4 ]  ];
 push @{ ${$_[ 0 ]}->{'%'}}, $#$::assertion;
 push @{ ${$_[ 1 ]}->{'{'}}, $#$::assertion;
 push @{ ${$_[ 2 ]}->{'|'}}, $#$::assertion;
 if( !( defined( $_[ 4 ] ))){ push @{ ${$_[ 3 ]}->{'}'}}, $#$::assertion; }}

 It makes use of autovivification (which also exists for
 arrays) and would be much more complicated to write without
 autovivification. I am currently rebuilding this system in
 Java and writing the corresponding code takes much longer in
 Java. The programmer needs to explain all the details to Java
 that Perl is able to grasp itself from the code the programmer
 writes.

 When I write »push @{ ... }«, Perl knows that »...« needs to
 be a reference to an array that needs to be allocated, if it is
 not yet there. Java gives you the garbage collector, so you do
 not have to release objects, Perl gives you autovivification,
 so that you do not even have to allocate them.

Stefan Ram - 04 Jun 2006 05:25 GMT
>Here is an excerpt from a knowledge base I wrote in Perl:
>It makes use of autovivification (which also exists for
>arrays) and would be much more complicated to write without

 Here is another example from the same projects that even
 uses more features of Perl and autovivification.

 I dynamically build an expression like
 »::root->{a}->{b}->...->{z}« and then use »eval« to build the
 whole path including all hashes required by autovivification,
 where the number of hashes required is only known at runtime.

 Eventually »$source« is stored at the new location within
 this map of maps of maps of ... maps.

my $buffer = '';
while( $psource =~ /(:|\/|[^:\/]+)/g ){ $buffer .= "->{'" . $1 . "'}"; }
my $expression = '\$::root' . $buffer;
my $place = eval( $expression ); ${$place}->{'#'}= $source;

 Without »=~«, without »eval« and without autovivification, it
 needs some more than four lines of Java to express the same
 thing in Java.
dimitar - 04 Jun 2006 12:13 GMT
>   Without »=~«, without »eval« and without autovivification, it
>   needs some more than four lines of Java to express the same
>   thing in Java.

Yep, that's right. If it is critical for your project that these
operations take less than four lines, then go use Perl.

FWIW one of the idioms for doing the 'autovivification' thing in Java is:

synchronized(masterMap) {
   if (!masterMap.contains(key)) {
       masterMap.put(key, new HashMap());
   }
}
masterMap.get(key).put(subkey, value);

it takes six lines, and it's thread-safe. Anything less and you might
loose data if more than one threads try to access the structure.

Dimitar
Stefan Ram - 04 Jun 2006 15:18 GMT
>FWIW one of the idioms for doing the 'autovivification' thing in Java is:
>synchronized(masterMap) {
[quoted text clipped - 3 lines]
>it takes six lines, and it's thread-safe. Anything less and you might
>loose data if more than one threads try to access the structure.

 It is still not quite the same, because it contains the fixed
 assumption "new HashMap()", while in Perl this also could be
 "new List()" or "new Integer()" depending on the client code
 used.

 If that would be possible in Java, one would be able to write

mainMap.get( key ).put( subKey, value );

 and get an autovivificated Map (as above), but also

mainMap.get( key ).add( value )

 and get an autovivificated List or

mainMap.get( key )+= 12

 and get an autovivificated Integer.

 Here's the complete Perl script:

use Data::Dumper;
$names->{ "branch" }->{ "account" } = 123;
$names->{ "branch1" }->[ 3 ] = 123;
$names->{ "branch2" } += 12;
print Data::Dumper::Dumper( $names ), "\n";

 and its output is:

$VAR1 = {
         'branch' => {
                       'account' => 123
                     },
         'branch1' => [
                        undef,
                        undef,
                        undef,
                        123
                      ],
         'branch2' => 12
       };

 Without autovivification, in Java, one needs some work of the
 programmer, for example, to create a nested array with a
 dimension given at runtime:

 For example, the following code builds an array with three
 dimensions of the extension 4, 5, and 6, respectively.
 The vivification happens recursively in »build« using
 »java.lang.reflect.Array.newInstance«. The number of arguments
 of »build« gives the dimension.

 A call to newInstance alone with the extensions will give
 an array object with the correct type, but its entries will
 still be empty and not other array objects. So, the recursion
 of »build« is needed to fill all array entries with other
 subarrays up to the lowest level.

public class Main
{
 public static int[] cdr( final int[] list )
 { return java.util.Arrays.copyOfRange( list, 1, list.length ); }

 public static java.lang.Object build( final int ... extensions )
 { final java.lang.Object array = java.lang.reflect.Array.newInstance
   ( java.lang.Integer.TYPE, extensions );
   for( int i = 0; i < extensions[ 0 ]; ++i )if( extensions.length > 1 )
   java.lang.reflect.Array.set( array, i, build( cdr( extensions )));
   else java.lang.reflect.Array.setInt(( int[] )array, i, i );
   return array; }

 public static void print( final java.lang.Object array )
 { for( int i = 0; i < java.lang.reflect.Array.getLength( array ); ++i )
   if( array.getClass().getName().startsWith( "[[" ))
   print( java.lang.reflect.Array.get( array, i )); else
   java.lang.System.out.print( java.lang.reflect.Array.getInt( array, i )); }

 public static void main( final java.lang.String[] args )
 { print( build( 4, 5, 6 )); }}
dimitar - 04 Jun 2006 16:31 GMT
Again, you seem to be trying to write Perl code in Java - it doesn't
work this way. There is a tradeoff between statically typed languages
(as Java) and dynamic languages as Perl - you lose something, you gain
another. If you want to use Java, you *have* to think differently than
in Perl. If no - Perl is just as good as any other Turing-complete language.

PS. I'm sorry to say it, but the Java code you posted sucks. Please read
http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html

PPS. There is no java.util.Arrays.copyOfRange(); as of JDK 1.3-1.5


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.