RogerBW's Blog

Perl Weekly Challenge 107: Self-Descriptive Methods 07 April 2021

I’ve been doing the Perl Weekly Challenges. The latest involved several sorts of introspection. (Note that this is open until 11 April 2021.)

TASK #1 › Self-descriptive Numbers

Write a script to display the first three self-descriptive numbers.

This is of course similar to task 2 of challenge 43, but not identical, as we need multiple answers; I rewrote the code from scratch. I eschewed most of the optimisations and just took the one that the SDN must end in zero. The example makes it clear that what's wanted is the first three SDNs in any base, and it's easiest just to assume base 10 and ignore the "number must have length equal to the base" constraint.

The algorithm is basically the same in each language: I have an array ns which is each digit in order, and an array d which is the number of times each digit occurs (so d[0] is the number of non-leading zeroes, etc.). If the number is self-describing these arrays will match (with any d in excess of the length of ns being zero). This code won't find SDNs above base 10, and it'll take a long time there. (But I was polite and didn't just pull results from OEIS A138480 or OEIS A108551 which would get the answer with much less work.)

In Raku:

sub sdn($count) {
  my @r;
  my $n=10;
  while (@r.elems < $count) {
    my @ns=map {$_+0}, sprintf('%d',$n).comb;
    my @d=(0) xx 10;
    map {@d[$_]++},@ns;
    my $sd=1;
    for 0..@ns.elems-1 -> $i {
      if (@d[$i] != @ns[$i]) {
        $sd=0;
        last;
      }
    }
    if ($sd && @ns.elems <= 9) {
      for @ns.elems..9 -> $i {
        if (@d[$i] != 0) {
          $sd=0;
          last;
        }
      }
    }
    if ($sd) {
      push @r,$n;
    }
    $n+=10;
  }
  return @r;
}

The others are basically the same, except that in Rust I built the two arrays in parallel

        let mut ns: Vec<usize>=vec![];
        let mut d: Vec<usize>=vec![0;10];
        for i in n.to_string().chars() {
            let k=i.to_digit(10).unwrap() as usize;
            ns.push(k);
            d[k] += 1;
        }

because it felt clearer.

TASK #2 › List Methods

Write a script to list methods of a package/class.

Eugh. If I need to do this it is generally a sign that something has gone Badly Wrong and I need to rethink my approach; it's a definite bad code smell if I see it in someone else's program. (I did once write a thing that used it, and it worked, but the code never got to the point of usability for people other than me.) So while I know that this is possible in Python and Ruby, though I believe not in Rust, I only actually did it in Perl and Raku.

Perl (making sure that each thing in the module's namespace is a method):

use List::Util;

no strict 'refs';
foreach my $cm (sort keys %List::Util::) {
  if (exists &{"List::Util::$cm"}) {
    print "$cm\n";
  }
}

Probably there's some way of getting at %modulename:: where "modulename" is a string variable rather than a literal piece of text, but I wasn't able to find it on a quick search and frankly wasn't enthusiastic enough to look very hard. (Also one would ideally want the contents of @modulename::ISA in order to get all the methods of the things one's inheriting from.)

Raku:

#! /usr/bin/perl6

use Pod::To::Text;

say Pod::To::Text.^methods.perl;

Full code on github.

See also:
Perl Weekly Challenge 43: rings and self-descriptive numbers


  1. Posted by RogerBW at 10:01am on 12 April 2021

    Part 1: mostly brute-forcing, some use of the table in Wikipedia but this isn't necessarily exhaustive. If I had a use for these I'd probably write a parser for the OEIS internal format. (Which I could use to solve a lot of these problems, really, but it wouldn't be much fun.)

    Part 2: many people feel less revulsion than I do. Though in any case

    %{"$class::"}

    will apparently get the job done

Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.

Search
Archive
Tags 1920s 1930s 1940s 1950s 1960s 1970s 1980s 1990s 2000s 2010s 3d printing action aeronautics aikakirja anecdote animation anime army astronomy audio audio tech aviation base commerce battletech beer boardgaming book of the week bookmonth chain of command children chris chronicle church of no redeeming virtues cold war comedy computing contemporary cornish smuggler cosmic encounter coup covid-19 cycling dead of winter doctor who documentary drama driving drone ecchi economics espionage essen 2015 essen 2016 essen 2017 essen 2018 essen 2019 existential risk falklands war fandom fanfic fantasy feminism film firefly first world war flash point flight simulation food garmin drive gazebo genesys geocaching geodata gin gkp gurps gurps 101 gus harpoon historical history horror hugo 2014 hugo 2015 hugo 2016 hugo 2017 hugo 2018 hugo 2019 hugo 2020 hugo-nebula reread in brief avoid instrumented life julie enfield kickstarter learn to play leaving earth linux liquor lovecraftiana mecha men with beards museum music mystery naval non-fiction one for the brow opera parody paul temple perl perl weekly challenge photography podcast politics postscript powers prediction privacy project woolsack pyracantha python quantum rail raku ranting raspberry pi reading reading boardgames social real life restaurant reviews romance rpg a day rpgs ruby rust science fiction scythe second world war security shipwreck simutrans smartphone south atlantic war squaddies stationery steampunk stuarts suburbia superheroes suspense television the resistance thirsty meeples thriller tin soldier torg toys trailers travel type 26 type 31 type 45 vietnam war war wargaming weather wives and sweethearts writing about writing x-wing young adult
Special All book reviews, All film reviews
Produced by aikakirja v0.1