RogerBW's Blog

Perl Weekly Challenge 131: Splitting and Splitting More 23 September 2021

I’ve been doing the Weekly Challenges. The latest involved splitting arrays and strings. (Note that this is open until 26 September 2021.)

Task 1: Consecutive Sub-Arrays

You are given a sorted list of unique positive integers.

Write a script to return list of arrays where the sub-arrays are consecutive integers.

Well, it's a little unexpected, but we can do that fairly cleanly. Here I'm using the Ruby version, since I haven't shown that for a while.

def csa(list)

The first sublist in the output holds the first value.

  o=[[list[0]]]

Skip that and proceed from the next value…

  1.upto(list.length-1) do |ni|

If it isn't the next expected value in a consecutive list, create a new empty sublist.

    unless o[-1][-1]+1 == list[ni] then
      o.push([])
    end

Then drop the value into the last sublist (either the newly created one or the previous one that already has content).

    o[-1].push(list[ni])
  end
  return o
end

It would be nice not to have to handle the indices directly, such as by using for n in lst, but then there'd be a conditional inside the loop to skip the first value. Or I could make a copy of the list and remove its first value. Neither of these is ideal. In the Rust and Python versions I explicitly define an iterator based on the list contents (which I hope should be implemented as a pointer rather than copying the whole list), call next() on it once to throw away the first value, then loop on what's left; I think Raku can do this too, with a bit more faff. The Rust version:

let mut i=list.iter();
i.next();
for n in i {

Ruby has things it calls "iterators", but they seem to be its term for method calls to iterate over a block, and I don't know if it has the gaps in it to let me get my pincers in between "define the things over which I will loop" and "loop over them".

Task 2: Find Pairs

You are given a string of delimiter pairs and a string to search.

Write a script to return two strings, the first with any characters matching the "opening character" set, the second with any matching the "closing character" set.

Key point here: the same character may occur in both "opening" and "closing" delimiters, in which case it's added to both output strings each time it occurs. Also there's no escaping or consideration of matched opening/closing pairs. So what I do is build a hash of "opening" and "closing" delimiter characters (a set, in the languages which support sets, which is all of them except Perl since I don't need to remove keys from the set this time), then check each character in the search string to see whether it appears in either (or both) sets.

In Perl/Raku one might reach for a regexp but punctuation characters are a pain, and one of the reasons I'm doing this in multiple languages is to get out of the habits formed by Perl where regexps and hash key lookups are ferociously optimised and one uses them for everything. Anyway, here's the Perl.

sub fp {
  my ($delims,$sample)=@_;

Iterate through the delimiter string noting opening and closing characters.

  my @d;
  foreach my $i (0..length($delims)-1) {
    $d[$i % 2]->{substr($delims,$i,1)}=1;
  }
  my @o;
  foreach my $s (split '',$sample) {

Test each character of the sample string for being in the openers and/or closers hashes, and push to a list if so.

    foreach my $x (0,1) {
      if (exists $d[$x]->{$s}) {
        push @{$o[$x]},$s;
      }
    }
  }

Turn the lists into strings.

  return [map {join('',@{$_})} @o];
}

The Raku is a bit uglier because I need to define the arrays explicitly so that they'll be mutable rather than default immutable Lists. In the Rust version, I'm especially happy with the char_indices method on the delims string, which returns a series of (index, character) tuples so that I don't have to manage the loop explicitly.

The PostScript is crude, with the open and close lists as separate variables (yeah, I should have put them in an array) and setting characters directly into fixed-length strings, but it works…

/fp {
    exch
    dup length
    dup dict /sopen exch def
    dict /sclose exch def
    /i 0 def
    {
        i 0 eq {
            sopen exch 1 put
        } {
            sclose exch 1 put
        } ifelse
        /i 1 i sub def
    } forall
    dup length
    dup string /copen exch def
    string /cclose exch def
    /iopen 0 def
    /iclose 0 def
    {
        dup
        dup sopen exch known {
            copen exch iopen exch put
            /iopen iopen 1 add def
        } {
            pop
        } ifelse
        dup sclose exch known {
            cclose exch iclose exch put
            /iclose iclose 1 add def
        } {
            pop
        } ifelse
    } forall
    cclose copen
} def

Full code on github.

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 advent of code 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 crime cthulhu eternal cycling dead of winter doctor who documentary drama driving drone ecchi economics en garde espionage essen 2015 essen 2016 essen 2017 essen 2018 essen 2019 essen 2022 essen 2023 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 2022 hugo-nebula reread in brief avoid instrumented life javascript julian simpson julie enfield kickstarter kotlin learn to play leaving earth linux liquor lovecraftiana lua mecha men with beards mpd museum music mystery naval noir 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 scala science fiction scythe second world war security shipwreck simutrans smartphone south atlantic war squaddies stationery steampunk stuarts suburbia superheroes suspense television the resistance the weekly challenge 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