Okay, so array_map(null, $array1, $array2, $array, ...) can be used to zip several arrays together. array_map(null, [1,2,3], [4,5,6]) == [[1,4], [2,5], [3,6]]. And then you've got the destructuring operator "..." and now you can have a general array-transpose operation:

$array = [[1,2,3], [4,5,6], [7,8,9]];
array_map(null, ...$array) == [[1,4,7], [2,5,8], [3,6,9]];

Which is all well, and good. But TIL:

array_map(null, ...[[a,b,c], [d,e,f], [g,h,i], [j,k,l]]) == [[a,d,g,j], [b,e,h,k], [c,f,i,l]]
array_map(null, ...[[a,b,c], [d,e,f], [g,h,i]]) == [[a,d,g], [b,e,h], [c,f,i]]
array_map(null, ...[[a,b,c], [d,e,f]]) == [[a,d], [b,e], [c,f]]
array_map(null, ...[[a,b,c]]) == [a, b, c]

4 arrays of 3 elements each becomes 3 arrays of 4 elements each
3 arrays of 3 elements each becomes 3 arrays of 3 elements each
2 arrays of 3 elements each becomes 3 arrays of 2 elements each
1 array  of 3 elements each becomes 1 array  of 3 elements each

One of these things is not like the others. And apparently it's not a bug. array_map(null, ...[[a,b,c]]) is equivalent to array_map(null, [a,b,c]) as it should be, but it was decided that the latter should be a no-op and just return its second argument unchanged.

Weedpacket

if(!is_array($new_array[0])) {
    $new_array = [$new_array];
}

🙃

(It's been years since I touched array_map() -- thankfully? -- and have never run into that syntax, and kind of hope I never have a reason to use it. 😉 )

Weedpacket You don't like functional programming?

Not a question of like/dislike, but more that I've not pursued it, other than reading/viewing a few high-level discussions at mainly theoretical levels -- no practical experience (intentionally) implementing it.

NogDog Ah; your mention of "hope" made me think you had something against it.

For fun and the record, here's the method where I hit the snag, with the workaround included, just to give an idea of what things would start to look like without the array_map.

public function ConjunctionVisit(Conjunction $expr)
{
	// Look for substitutions to Conjunction-bound variables. If this happens (it shouldn't, but at present
	// there's nothing to stop it), we first replace the Conjunction's colliding bound variables with
	// newly-minted ones, then update its expression to use the newly-minted variables in place of
	// the existing ones. Then we can apply the substitutions we were actually passed.
	$new_substitutions = [];
	foreach($this->substitutions as [$var,])
	{
		if(in_array($var, $expr->variables, true))
		{
			$new_substitutions[] = [$var, LVariable()];
		}
	}
	if(empty($new_substitutions))
	{
		// No substitutions of bound variables. Business as usual, then.
		$expression = $expr->expression->accept($this);
		return ($expression === $expr->expression) ? $expr : Conjunction($expression, $expr->variables);
	}

// If the number of new substitutions is 1 then array_map(null, ...) breaks down
// (this is known but undocumented behaviour: array_map(null, array) is a no-op)
if(count($new_substitutions) == 1)
{
	$existing_variables = [$new_substitutions[0][0]];
	$new_variables = [$new_substitutions[0][1]];
}
else
{
	[$existing_variables, $new_variables] = array_map(null, ...$new_substitutions);
}
$new_variables = array_map(function($var)use($existing_variables, $new_variables)
{
	$i = array_search($var, $existing_variables, true);
	return ($i !== false) ? $new_variables[$i] : $var;
}, $expr->variables);
return Conjunction($expr->expression->accept(Substituting(...$new_substitutions, ...$this->substitutions)), $new_variables);
}

Weedpacket your mention of "hope" made me think you had something against it

Nah, more that I had recollections of trying to use array_map() for something way back when and finding it less than easy to comprehend at the time, and that this twist on it looked like it might cause a similar mind-ache. 🙂 (Hopefully I'm a bit better programmer now and maybe it would come more easily, but the situation has not arisen since then where I ended up on the manual page for array_map().)

    3 months later

    TIL: you can flip an image horizontally just via CSS:

    <img src='/smurf.gif' height="150px" style="transform: scaleX(-1);">
    

    PS: Yes, I'm using a "Smurf" image for an internal tool on a project which ended up with the acronym "SMRF". 🙂

    18 days later

    NogDog You could substitute an image of Papa Smurf over the Christmas season.

      12 days later

      TIL: looks like strtotime() ignores fractional seconds when converting an ISO 8601 timestamp:

      $ php -r 'var_dump(strtotime("2021-09-21T22:19:51.689+00:00"));'
      int(1632262791)
      $ php -r 'var_dump(strtotime("2021-09-21 15:19:52"));'
      int(1632262792)

        Also learned that floor(), ceil(), and round() return floats for some reason:

        $ php -r 'var_dump(ceil("1.1"));'
        float(2)
        $ php -r 'var_dump(floor("1.1"));'
        float(1)
        $ php -r 'var_dump(round("1.1"));'
        float(1)

        And now that you've made me look at the manual, TIL that you can specify a negative precision for round():

        20:29 $ php  -a
        Interactive shell
        
        php > $foo = round(1234.567, -2);
        php > var_export($foo);
        1200.0
        php >
        

        I've had a rule of thumb which is "don't start by assuming the guy before you was totally incompetent". I've got a more concise name for it now; Chesterton's Fence.

        I admit mine is a little more general and spills over into another rule of thumb of mine: "If you think you have to force it you're probably doing it wrong."

        7 days later

        TIL the interesting attribute of the number 6174: https://youtu.be/d8TRcZklX_Q

        For the fun of it, I came up with this PHP script, which I'm sure could be improved/streamlined. 🙂

        <?php
        // Fun with 6174
        
        if(empty($argv[1])) {
          die("Usage: ".basename(__FILE__)." nnnn\n    where 'nnnn' is a 4-digit number\n");
        }
        if(!preg_match('/^[0-9]{4}$/', $argv[1])) {
          die("Usage: " . basename(__FILE__) . " nnnn\n    where 'nnnn' is a 4-digit number\n");
        }
        $digits = str_split($argv[1]);
        $unique = array_unique($digits);
        if(count($unique) == 1) {
          die("The number cannot use the same value for all 4 digits.\n");
        }
        while(true) { // Danger, Will Robinson!
          sort($digits);
          $asc = implode('', $digits);
          rsort($digits);
          $desc = implode($digits);
          $diff = $desc - $asc;
          $diff = str_pad($diff, 4, '0', STR_PAD_LEFT);
          echo "$desc - $asc = $diff\n";
          if($diff == '6174') {
            die("7641 - 1467 = 6174\n");
          }
          $digits = str_split($diff);
        }
        

        Weedpacket Now try and find a number that gives the longest path to 6174.

        My test came up with a max of 7 iterations, and applied to 2184 numbers. A bunch of those are duplicates of a sort, since 1234 will be the same as 4321 or 1432, etc.

        PS: Further coding determined (assuming no bugs) there are 116 unique sets of 4 digits that have 7 iterations.

        5 days later

        TIL: You can use (at least some?) expressions in an SQL order by clause, e.g.:

        select predicate_type_id
        from some_schmea.predicate_type
        order by mod(predicate_type_id, 2), predicate_type_id
        

        Output:

        4
        6
        8
        10
        12
        14
        16
        1
        7
        9
        11
        13
        15
        17
        
        2 months later

        TIL that not sanitizing inputs can have far-reaching and long-lasting effects.

        Maybe I knew that in 2013, even. #WhyDidntTheApacheGuys