Hello there, everyone!

I'm running late but I'm doing the advent of code 2023 at adventofcode.com and for the first day, I ended up with the following. I"m wondering if someone could point out what I could have done to make it more efficient/better.

Day 1:

The newly-improved calibration document consists of lines of text; each line originally contained a specific calibration value that the Elves now need to recover. On each line, the calibration value can be found by combining the first digit and the last digit (in that order) to form a single two-digit number.

$input = "start
ckmb52fldxkseven3fkjgcbzmnr7
gckhqpb6twoqnjxqplthree2fourkspnsnzxlz1
2onetwocrgbqm7
frkh2nineqmqxrvdsevenfive
four9two";

$total = 0;
$separator = "\r\n";
$line = strtok($input, $separator);
while ($line !== false) {
    $line = strtok( $separator );
    foreach (str_split($line) as $char) {
        if (is_numeric($char)) {
            if(!ISSET($none)){
                $none = $char;
            }
            $ntwo = $char;
            
        }
    }
    $total = $none.$ntwo + $total;
    echo $total."<br>";
    UNSET($none);
    UNSET($ntwo);
}

    Fun with regular expressions: 🙂

    <?php
    
    $input = "start
    ckmb52fldxkseven3fkjgcbzmnr7
    gckhqpb6twoqnjxqplthree2fourkspnsnzxlz1
    2onetwocrgbqm7
    frkh2nineqmqxrvdsevenfive
    four9two";
    
    $numbers = [];
    foreach(preg_split('/\r?\n/', $input) as $line) {
      preg_match('/^[^\d]*(\d).*(\d)[^\d]*$/', $line, $matches);
      if(!empty($matches)) {
        $numbers[] = (int) $matches[1].$matches[2];
      }
    }
    echo "Found these numbers: ".implode(', ', $numbers)."\n";
    echo "The total is: ".array_sum($numbers)."\n";
    

    Result:

    $ php ~/Desktop/challenge.php 
    Found these numbers: 57, 61, 27
    The total is: 145
    

    Here's a variation on @NogDog's code with a simpler regex. I wonder if it might be a bit faster, but not sure it'll work in every situation. For example, it won't find any numbers in a line that has only one digit.

    $input = "start
    ckmb52fldxkseven3fkjgcbzmnr7
    gckhqpb6twoqnjxqplthree2fourkspnsnzxlz1
    2onetwocrgbqm7
    frkh2nineqmqxrvdsevenfive
    four9two";
    
    $numbers = [];
    foreach(preg_split('/\r?\n/', $input) as $line) {
      echo "line: $line\n";
      $match_count = preg_match_all('/\d{1}/', $line, $matches);
      if($match_count >= 2) {
        $numbers[] = intval($matches[0][0] . $matches[0][$match_count - 1]);
      } else {
        // echo "no numbers\n";
      }
    }
    echo "Found these numbers: ".implode(', ', $numbers)."\n";
    echo "The total is: ".array_sum($numbers)."\n";

    sneakyimp
    Taking the preg_match_all and folding it into the following if:

      if(preg_match_all('/\d/', $line, $matches) >= 2) {
        $numbers[] = array_shift($matches[0]).array_pop($matches[0]);

    Decided I could reduce mine to a single regex... 🙂

    $numbers = [];
    preg_match_all('/^[^\d]*(\d).*(\d)[^\d]*$/mU', $input, $matches, PREG_SET_ORDER);
    foreach($matches as $match) {
      $numbers[] = (int) $match[1].$match[2];
    }
    

    Weedpacket

    I had considered using array_pop and array_shift, but thought that the array manipulations might take more time than the lookup. I like the very compact code, though.

      @schwim
      The preg examples we've provided here are probably faster than your code. However, I believe they might consume a lot more memory than your approach because they create a large var of all the lines in the input data and then a $matches array containing all the matched digits.

      sneakyimp Heh...some of the team I'm part of at work are writing Rust code to consume/transform medical insurance plans' billing rate data -- from JSON files that can be hundreds of megabytes and more -- doing everything they can to read from a stream and minimize what gets stored in memory. A lot of it goes over my head, but they're doing it much to everyone else's amazement. (All a result of the Transparency in Costs initiative that the US govt. has put into place.)

      But yeah, if the data to be processed was in a large file (for some undefined value of "large"), you'd probably want to create a file handle and use fgets() or such to process one line at a time.

      NogDog
      I recently helped a client clean up their CDN. They had some 40M files divided between two data centers. The API is fairly old -- our code has been running for about 10 years, stuffing assets into the cdn. Client wanted a sanity check to see if there were 'orphaned' files in there (i.e., we had no db record of them or we have db record and there's no file) so I wrote a script to simply list the containers and files that were in each data center and export this to a CSV file. The script took a about 4 hours on one data center and 2 on the other, just to list the files. The CSV file was 4.5GB.

        Write a Reply...