3

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?

Homerian
  • 183
  • 4
  • Not sure what value the *common number variable* is tracking? Is it a single (general) value you're tracking, e.g. word-with-the-most-counts in a text passage (i.e. the mode), or is it a ***per-key*** value, i.e. you want to update/replace a (lower) value held in the hash and/or array if-and-only-if a higher value is seen. – jubilatious1 Oct 26 '22 at 19:47
  • 1
    If answers so far cover what you need then fair enough. If not, please consider improving your question. I *wanted* to try to help but haven't been able to figure out what you are trying to do, nor what to say other than this comment. The SO norm of every question containing a [MRE] would be a good first step to help me (and perhaps others) understand what you are trying to do and ways to do it. – raiph Oct 26 '22 at 22:39

2 Answers2

2

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. ;)

Scimon Proctor
  • 4,558
  • 23
  • 22
  • 2
    hi your for loop syntax is Perl-like but it's not quite Perl either (not NQP but literally :)) – Mustafa Aydın Oct 26 '22 at 18:55
  • 1
    »ö«.oO ( "Is Scimon's code Perl? Nope. And no, 'tain't Raku neither. Is it Sumerian? What the?!? ["In linguistic morphology, inflection (or inflexion) is a process of word formation in which a word is modified to express different grammatical categories."](https://en.wikipedia.org/wiki/Sumer#:~:text=it%20was%20not%20an%20inflected%20language) Ah. If you say so. Anyway, nope. Homerian? What??? Ah, so that's part of what inspired the Sumerian weirdness? Anyway, still, nope. NQP? No! NQPE? NOPE! NOPE?? As the name of a Rakoon's Raku dialect? Well, at last, you're warm... *NOT*. **NOPE!!!**" ) – raiph Oct 27 '22 at 10:04
  • @MustafaAydın https://docs.raku.org/syntax/loop – jubilatious1 Oct 27 '22 at 16:49
  • 1
    @jubilatious1 thanks i was more thinking like `for @vals -> $a, $b? { ... }` – Mustafa Aydın Oct 28 '22 at 08:23
  • 1
    Oops yes. My bad. But the point was more about the rotor aspect anyway. I am only on my phone today, will try and get the answer updated to actual Raku at some point. – Scimon Proctor Oct 28 '22 at 11:03
0

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 word frequencies 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

jubilatious1
  • 1,999
  • 10
  • 18