The suggested solution to this thread seems odd to me. It confuses a storage structure with information about the elements, and doesn't use the power of perl6.

An associative array is useful because non-integer indexes are possible and hashing makes storage efficient. This makes referencing data about eg a person using the person's name. If the key to the hash is not something that is intrinsicly useful, why use a hash. Just use another array.

The problem posed here seems to me to be about ways to sort the elements of a hash. So why not use .sort on the pairs?

If a Hash is being used for storage and the order in which the elements are added to the hash is important, then this is meta data that should be explicitly stored in the hash together with element. (Lets ignore algorithmic efficiency questions and look at perl6 idoms).

For example (hopefully the example below will work by just pasting, but email reformating may mangle lines):

#!/usr/bin/env perl6

use v6.c;

my %h = <aaa ggg zzz hhh> Z=>

    %(:create-ord(1), :payload<abc>, :stuff<more info>),

    %(:create-ord(3), :payload<1b>, :stuff<an array of words>),

    %(:create-ord(2),:payload<abc>,:stuff(a longer array of words>),

    %(:create-ord(4),:payload<zzz>,:stuff<ok>);

# this zips (Z) two lists in combination with the pair creation operator (=>) to create a list of pairs, which is stored as a hash.

# the idiom :key{$value} creates a pair, so :key<value> makes the value part a string, or :key<one two three> a list of strings

.say for %h;

#output

#hhh => {create-ord => 4, payload => zzz, stuff => ok}
#ggg => {create-ord => 3, payload => 1b, stuff => (an array of words)}
#zzz => {create-ord => 2, payload => abc, stuff => (a longer array of words)}
#aaa => {create-ord => 1, payload => xyz, stuff => (more info)

# In the above code line, 'for %h' sends a list of pairs to .say , and .say magically formats each pair presented to it

#Now we can list these in any sorted order. First by the value of the keys in alphabetic order

.say %h.sort({ .keys });

#aaa => {create-ord => 1, payload => xyz, stuff => (more info)}
#ggg => {create-ord => 3, payload => 1b, stuff => (an array of words)}
#hhh => {create-ord => 4, payload => zzz, stuff => ok}
#zzz => {create-ord => 2, payload => abc, stuff => (a longer array of words)}

# note here that sort receives a list of pairs, but we need to run some code to access the bits we want hence .sort( { ... } )

# Now we can sort in order of creation, the create-ord field

.say for %h.sort( { .kv.map( -> $k,%v { %v<create-ord> }) });

#aaa => {create-ord => 1, payload => xyz, stuff => (more info)}
#zzz => {create-ord => 2, payload => abc, stuff => (a longer array of words)}
#ggg => {create-ord => 3, payload => 1b, stuff => (an array of words)}
#hhh => {create-ord => 4, payload => zzz, stuff => ok}

# inside the sort I have a .kv.map because the hash value is stored as a Seq not a Hash :(

# and I cant find a better way of coercing the value part back to a Hash :(    There may be a better way for the coercion.

# inside the .map(...) the '-> $k, %v' is a signature to the '{ ... }' block and binds the two items created by .kv to $k, %v

#So given we can access the inner hash, we can sort on other things, such as the length of the list of words in :stuff

.say for %h.sort( { .kv.map( -> $k,%v { %v<stuff>.elems }) });
#hhh => {create-ord => 4, payload => zzz, stuff => ok}
#aaa => {create-ord => 1, payload => xyz, stuff => (more info)}
#ggg => {create-ord => 3, payload => 1b, stuff => (an array of words)}
#zzz => {create-ord => 2, payload => abc, stuff => (a longer array of words)}

# and if you want the reverse order then

.say for %h.sort( { .kv.map( -> $k,%v { %v<create-ord> }) }).reverse;

#hhh => {create-ord => 4, payload => zzz, stuff => ok}
#ggg => {create-ord => 3, payload => 1b, stuff => (an array of words)}
#zzz => {create-ord => 2, payload => abc, stuff => (a longer array of words)}
#aaa => {create-ord => 1, payload => xyz, stuff => (more info)}


On Tuesday, October 03, 2017 09:06 PM, Andrew Kirkpatrick wrote:
Thanks, your script enticed me to explore different ways of
constructing a hash table. I dimly recall something about map having
access to an index variable, but couldn't find it documented so maybe
I was dreaming. The process of figuring out these approaches
highlighted that so much perl6 documentation on the web is outdated. I
guess what the perl6.org site needs is more examples. Rosettacode was
also useful.

#!/usr/bin/env perl6

#`{
   Hashes do not print in the order they are created.  it is a Perl 6 thing.
   To overcome this, create an index of the hash.
}

my @SmtpIndex =
    qw[ DebugTrace smtp port username password from to Subject Text FileName ];

my %Smtp =
   [ "{ @SmtpIndex[0] }" => "1",
     "{ @SmtpIndex[1] }" => "smtps://smtp.zoho.com",
     "{ @SmtpIndex[2] }" => "465",
     "{ @SmtpIndex[3] }" => 'la...@zoho.com',
     "{ @SmtpIndex[4] }" => "NaYukYukYuk",
     "{ @SmtpIndex[5] }" => 'la...@zoho.com',
     "{ @SmtpIndex[6] }" => @['cu...@zoho.com','m...@zoho.com'],
     "{ @SmtpIndex[7] }" => "Stooges",
     "{ @SmtpIndex[8] }" => "Certainly!",
     "{ @SmtpIndex[9] }" => @[""] ];

sub output(%hash, @index=@SmtpIndex) {
     for @index -> $key {
         printf "%10s = %s\n", $key, %hash{$key};
     }
}

my @SmtpValues = %Smtp{@SmtpIndex};

my %Smtp2 = do {
     my $index = 0;
     @SmtpValues.map: { "{ @SmtpIndex[$index++] }" => $_ };
};

my %Smtp3 = gather for 0..@SmtpIndex.elems-1 {
     take @SmtpIndex[$_] => @SmtpValues[$_].Str;
};

my %Smtp4 = @SmtpIndex Z=> @SmtpValues;

# These are all equivalent
# output(%Smtp);
# output(%Smtp2);
# output(%Smtp3);
output(%Smtp4);


On 3 October 2017 at 07:23, ToddAndMargo <toddandma...@zoho.com> wrote:
Hi All,

I created a keeper not on hash indexing.  I though
maybe you guys would find it interesting, if for nothing
else, for the syntax used

-T


Perl6: Indexing a hash:

<code>
#!/usr/bin/env perl6

#`{
   Hashes do not print in the order they are created.  it is a Perl 6 thing.
   To overcome this, create an index of the hash.
}

my @SmtpIndex =
    qw[ DebugTrace smtp port username password from to Subject Text FileName
];

my %Smtp =
   [ "{ @SmtpIndex[0] }" => "1",
     "{ @SmtpIndex[1] }" => "smtps://smtp.zoho.com",
     "{ @SmtpIndex[2] }" => "465",
     "{ @SmtpIndex[3] }" => 'la...@zoho.com',
     "{ @SmtpIndex[4] }" => "NaYukYukYuk",
     "{ @SmtpIndex[5] }" => 'la...@zoho.com',
     "{ @SmtpIndex[6] }" => @['cu...@zoho.com','m...@zoho.com'],
     "{ @SmtpIndex[7] }" => "Stooges",
     "{ @SmtpIndex[8] }" => "Certainly!",
     "{ @SmtpIndex[9] }" => @[""] ];

for @SmtpIndex -> $key { printf "%10s = %s\n", "$key", "%Smtp{$key}"; }
</code>


$ HashIndexTest.pl6
DebugTrace = 1
       smtp = smtps://smtp.zoho.com
       port = 465
   username = la...@zoho.com
   password = NaYukYukYuk
       from = la...@zoho.com
         to = cu...@zoho.com m...@zoho.com
    Subject = Stooges
       Text = Certainly!
   FileName =

Reply via email to