4

I am currently trying to use hashes in an array to find the keys and values of each specific item in the array. I am able to do this and both the keys and the values are separate when I haven't sorted the array, but when I create a sorted array such as:

my @sorted_pairs = %counts{$word}.sort(*.value);

It binds the values together. Is there a method for sorted hash values that allow the pairs to be split into separate entities within the array? I want to be able to access the "word" string and the count or number of times that word was seen as an integer, separately.

I am using this source as a reference. I have tried a handful of these methods and while it does seem to sort the array by numeric value given the output:

sorted array : [do => 1 rest => 1 look => 1 wanted => 1 give => 1 imagine => 2 read => 2 granted => 2 ever => 2 love => 2 gonna => 2 feel => 2 meant => 2 like => 2 you => 2 live => 3 wrote => 3 come => 3 know => 3 are => 3 mom => 4]

it doesn't separate the key and value from one another.

Elizabeth Mattijsen
  • 25,654
  • 3
  • 75
  • 105
Homerian
  • 183
  • 4
  • 2
    So what does the %counts hash contain *exactly*? What does `dd %counts{$word}` give? – Elizabeth Mattijsen Apr 28 '22 at 09:38
  • 2
    Not quite sure I understand what you are doing here ... please can you provide a self-contained [MRE](https://stackoverflow.com/help/minimal-reproducible-example)? At first glance, it looks like a [BagHash](https://docs.raku.org/type/BagHash#Note_on_reverse_and_ordering) may be applicable . – librasteve Apr 28 '22 at 20:27
  • 1
    Are you just talking about how, for example, the `value1 key2` in `key1 => value1 key2 => value2` appear not to be separate from each other? If so, and the data behind `key1 => value1 key2 => value2` is a hash, or a list of pairs, then the apparent lack of separation is just a display thing. The data is pairs, with separate keys and values, and we can easily explain that. But then that's got nothing to do with sorting. More generally, your prose description of your problem is ambiguous in lots of ways. The standard way to eliminate ambiguity in an SO question is to provide a [MRE]. – raiph Apr 29 '22 at 02:40
  • 1
    For the "word-counting" answer provided, if you want to access the first element of the `@aoh` array you would write: `say @aoh[0];`. To get the key of the first element it would be: `say @aoh[0].key;`, to get the value it would be: `say @aoh[0].value;`. Ranges also work: `.put for @aoh[0..3];` gives you two columns of tab-separated key/value data (first 4 "rows" of the `@aoh` array). – jubilatious1 Apr 29 '22 at 15:07

1 Answers1

6

Word-counting in Raku

You might want to save your results as a (Bag-ged) array-of-hashes (pairs?), then print out either .keys or .values as necessary.

raku -e 'my @aoh = words.Bag.pairs.sort(*.values).reverse; \
        .say for @aoh;'  Ishmael.txt

Sample Input (Ishmael.txt):

Call me Ishmael.  Some years ago--never mind how long precisely --having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.  It is a way I have of driving off the spleen, and regulating the circulation.  Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people's hats off--then, I account it high time to get to sea as soon as I can.

Using the code above you get the following Output (full output truncated by specifying $_.value >= 4):

raku -e 'my @aoh = words.Bag.pairs.sort(*.values).reverse; \
        .say if ($_.value >= 4) for @aoh ;'  Ishmael.txt
I => 8
the => 7
and => 6
of => 4
to => 4
a => 4

And it's simple enough to return just .keys by changing the second statement to .keys.put for @aoh:

$ raku -e 'my @aoh = words.Bag.pairs.sort(*.values).reverse; \
          .keys.put if ($_.value >= 4) for @aoh ;'  Ishmael.txt
I
the
and
a
to
of

Or return just .values by changing the second statement to .values.put for @aoh:

$ raku -e 'my @aoh = words.Bag.pairs.sort(*.values).reverse; \
          .values.put if ($_.value >= 4) for @aoh ;'  Ishmael.txt
8
7
6
4
4
4

[Note: the above is a pretty quick-and-dirty example of word-counting code in Raku. It doesn't handle punctuation, capitalization, etc., but it's a start.]

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

jubilatious1
  • 1,999
  • 10
  • 18
  • Instead of `.reverse` sort by the negative of value. `-*.value` – Brad Gilbert Apr 29 '22 at 17:35
  • @BradGilbert interesting. I used `.sort(*.values).reverse;` while you used `.sort(-*.value);`. FYI, `.sort(-*.values);` doesn't work, and I'm at a loss to explain the discrepancy (and/or lack of an error message). – jubilatious1 Apr 30 '22 at 23:08