Home > Software design >  Is there a Raku function/method that would allow a sorted hash array to be iterated upon and determi
Is there a Raku function/method that would allow a sorted hash array to be iterated upon and determi

Time:10-27

I am currently working with a hash array that I have sorted by its keys and values. I have been successful in splitting the hash up such that I can grab the key and value separately. I have created a loop function that iterates through the array of keys and values. Additionally, I have a most common number variable that keeps track of the hash value and ideally updates whenever it iterates through the loop and finds a value greater than the current value in the most common number variable. This is what my code looks like:

my $MCNum = 0;
my @sorted_pairs = %counts{$word}.sort: *.kv;
loop (my $i = 0; $i < @sorted_pairs; $i  ) {
            say "i: ", @sorted_pairs[$i].values;
            say "i 1 ",@sorted_pairs[$i 1].values;
        if @sorted_pairs[$i].values < @sorted_pairs[$i 1].values {
            $MCNum = @sorted_pairs[$i 1].values;
            $best_word = @sorted_pairs[$i 1].keys;
            say "MCNumber is: ", $MCNum;
        }  

Which gives this output when I run the program:

Sorted Hash Array: [90's => 1 at => 1 dance => 1 did => 1 does => 1 doesn't => 1 don't => 1 droid => 1 dubwise => 1 feat => 1 hasn't => 1 if => 1 is => 5 letters => 1 life => 1 like => 1 man => 1 me => 5 monsterman => 1 my => 2 scenes => 1 sensation => 1 so => 3 song => 1 survives => 1 theme => 1 triangle => 1 weather => 1 would => 1 y'all => 1 you => 10 your => 1]
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (5)
i: (5)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (5)
i: (5)
i 1 (1)
i: (1)
i 1 (2)
i: (2)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (3)
i: (3)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (1)
i: (1)
i 1 (10)
i: (10)
i 1 (1)
i: (1)
i 1 ()

This leads to my confusion as I assume that the value should be skipped when it encounters 1's, but when it sees 2, 5, and/or 10, the most common number variable value should be updated. Instead, I've noticed that when running the program, it either never updates as shown in the code, or it consistently updates the variables regardless of if the number is smaller or larger. What am I missing?

CodePudding user response:

I think you want to be using value and key inside the loop instead of values and keys. The latter return lists and when you do a numeric comparison @sorted_pairs[$i].values < @sorted_pairs[$i 1].values you end up comparing the lengths of these lists.

Which is always one.

Also you could do something like :

my $MCNum = 0;
my @sorted_pairs = %counts{$word}.sort.rotor(2 => -1).map(*.kv);
for my $a, $b ( @sorted_pairs ) {
    if $a.value < $b.value {
        $MCNum = $b.value;
        $best_word = $b.key;
        say "MCNumber is: ", $MCNum;
    }
}

rotor splits a list like thing into sub lists and if you set the cycle skip length to a negative it skips back an element so.

(1,2,3,4,5).rotor(2 => -1) ~~ ((1,2),(2,3),(3,4),(4,5))

Generally if I see an old school C style loop in Raku I figure something can be simplified. ;)

CodePudding user response:

I'm uncertain as to the question, but it might be that you're getting involved with arrays too early in your workflow.

Let's say you have a list of words from here:

https://stackoverflow.com/a/72053359/7270649

I => 8
the => 7
and => 6
of => 4
to => 4
a => 4

If you use .put instead of .say in the code-producing output above, you get tab-separated output instead. A one-liner can take that tab-separated output easily and process it for you. Lets say we concatenate the output, so we have 2 copies, with the second copy's values incremented by 1:

I   8
the 7
and 6
to  4
of  4
a   4
I   9
the 8
and 7
to  5
of  5
a   5

Appending into a hash (%counts) gives us the following (blank spaces added for clarity):

~$ raku -e 'my %counts; for lines.map(*.words) { %counts.=append($_) };  \
            .say for %counts.sort: -*.value.max;' file

I => [8 9]
the => [7 8]
and => [6 7]
to => [4 5]
a => [4 5]
of => [4 5]

From the code above, all you need is an extra statement to either 1). overwrite hash values (conditionally) with a single max value per key or 2. overwrite hash values (conditionally) with a single sum value per key:

#Max

~$ raku -e 'my %counts; for lines.map(*.words) { %counts.=append($_) };  \
         for %counts.kv -> $k,$v { if $v.elems > 1 {%counts{$k} = $v.max }};  \
         .say for %counts.sort: -*.value;'  file

I => 9
the => 8
and => 7
to => 5
a => 5
of => 5
#Sum

~$ raku -e 'my %counts; for lines.map(*.words) { %counts.=append($_) };  \
         for %counts.kv -> $k,$v { if $v.elems > 1 {%counts{$k} = $v.sum }};  \
         .say for %counts.sort: -*.value;'  file

I => 17
the => 15
and => 13
of => 9
a => 9
to => 9

Then...you can assign to an array. So maybe this has been helpful, at least to give you a few more 'strategic' options regarding hashes (and eventually...arrays).

https://docs.raku.org/language/hashmap#In_place_editing_of_values

  • Related