【 #ゆめみからの挑戦状 ★第5弾】解答の紹介と総括

ツイート貼りすぎてページロード重いですがご容赦ください

# 問題

@Yametaro さんメインで定期開催していた [#ゆめみからの挑戦状](https://twitter.com/hashtag/%E3%82%86%E3%82%81%E3%81%BF%E3%81%8B%E3%82%89%E3%81%AE%E6%8C%91%E6%88%A6%E7%8A%B6) ですが，今回は私から PHP に関連する問題として出題させていただきました。

https://twitter.com/yumemiinc/status/1567724142811820033

```php
<?php

$in = [
    ['2nd' => 'two', 'four' => '4th'],
    'three' => '3rd',
    ['one' => '1st'],
    '10th' => 'ten',
    ['6th' => 'six'],
    '5th' => 'five',
    'seven' => '7th',
    ['fourteen' => '14th', '11th' => 'eleven'],
    ['8th' => 'eight'],
    'thirteen' => '13th',
    '12th' => 'twelve',
    'nine' => '9th',
    ['15th' => 'fifteen'],
];

// 以下と同じ配列を $in から作って出力してください
//
// [
//     '1st' => 'one',
//     '2nd' => 'two',
//     '3rd' => 'three',
//     '4th' => 'four',
//     '5th' => 'five',
//     '6th' => 'six',
//     '7th' => 'seven',
//     '8th' => 'eight',
//     '9th' => 'nine',
//     '10th' => 'ten',
//     '11th' => 'eleven',
//     '12th' => 'twelve',
//     '13th' => 'thirteen',
//     '14th' => 'fourteen',
//     '15th' => 'fifteen',
// ]
```

直近が壮大な大喜利問題でしたが，今回は割と真面目です😂
難易度を極端に上げてもアレなので，「あんまり PHP に詳しくなくても一応解ける」ぐらいに調整しました。

「数値添字配列」と「連想配列」が区別されずにぐっちゃぐちゃになる PHP らしい問題です。
（内部的には速度最適化のために区別されているらしいですが，ユーザからは見えにくい部分です）

# 思考のポイント

今回問われる観点は以下の 4 つです。

- どのように再帰もしくは平坦化するか
- どのように `1st` `2nd` `3rd` のような数字付き省略形序数詞を判定するか
- どのように値とキーを反転させるか
- どのようにソートさせるか

よく見られたパターン・個人的に紹介したいパターンについて記載します。
<del>面倒なので今回はマニュアルとかへのリンクは割愛します</del>

## どのように再帰もしくは平坦化するか

### `array_walk_recursive` に任せる

一番 PHP らしい方法ですね。圧倒的にこれを使った解答が多かったです。

**「ネストしている末端部分のキーバリューペアのみを取りたい」**

その要求をドンピシャで叶えてくれます。但し，新しい配列をリターンするのではなく，既存配列を手続き的に書き換えるデザインとなっており，新しい変数に入れるためにはコールバックに `use` での参照変数が必要になるなど，微妙に癖が強い部分はありますね。

```php
<?php

$in = [
    ['2nd' => 'two', 'four' => '4th'],
    'three' => '3rd',
    ['one' => '1st'],
    '10th' => 'ten',
    ['6th' => 'six'],
    '5th' => 'five',
    'seven' => '7th',
    ['fourteen' => '14th', '11th' => 'eleven'],
    ['8th' => 'eight'],
    'thirteen' => '13th',
    '12th' => 'twelve',
    'nine' => '9th',
    ['15th' => 'fifteen'],
];

$out = [];
array_walk_recursive($in, function ($value, $key) use (&$out) {
    $out[$key] = $value;
});

echo json_encode($out, JSON_PRETTY_PRINT);
/*
{
    "2nd": "two",
    "four": "4th",
    "three": "3rd",
    "one": "1st",
    "10th": "ten",
    "6th": "six",
    "5th": "five",
    "seven": "7th",
    "fourteen": "14th",
    "11th": "eleven",
    "8th": "eight",
    "thirteen": "13th",
    "12th": "twelve",
    "nine": "9th",
    "15th": "fifteen"
}
*/
```

### `RecursiveArrayIterator` `RecursiveIteratorIterator` に任せる

`array_walk_recursive` の設計上の問題点を克服し，値をリターンする使い方が出来る方法です。　PHP 標準の再帰イテレータの機能を使っています。 これもそこそこ使用者が居たように見えました。

**<font color=blue>PHP 8.1 から `...` がイテレータの展開に対応</font>し，めちゃくちゃ気持ちよく書けるようになりました。**

```php
<?php

$in = [
    ['2nd' => 'two', 'four' => '4th'],
    'three' => '3rd',
    ['one' => '1st'],
    '10th' => 'ten',
    ['6th' => 'six'],
    '5th' => 'five',
    'seven' => '7th',
    ['fourteen' => '14th', '11th' => 'eleven'],
    ['8th' => 'eight'],
    'thirteen' => '13th',
    '12th' => 'twelve',
    'nine' => '9th',
    ['15th' => 'fifteen'],
];

// PHP 8.1 からはなんとこれでいい！
$out = [...new RecursiveIteratorIterator(new RecursiveArrayIterator($in))];

// PHP 8.0 まではこう
//   - 第 2 引数に false を渡すと array_merge っぽいキー合成になる （... と同じ）
//   - 第 2 引数に true を渡すと array_replace っぽいキー合成になる
// 今回は文字列キーしかないのでどちらでも同じ
//
// $out = iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator($in)), false);

echo json_encode($out, JSON_PRETTY_PRINT);
/*
{
    "2nd": "two",
    "four": "4th",
    "three": "3rd",
    "one": "1st",
    "10th": "ten",
    "6th": "six",
    "5th": "five",
    "seven": "7th",
    "fourteen": "14th",
    "11th": "eleven",
    "8th": "eight",
    "thirteen": "13th",
    "12th": "twelve",
    "nine": "9th",
    "15th": "fifteen"
}
*/
```

### `array_filter` `array_replace` を使った合成

今回は「無限にネストした配列に対応できるようにしてください」とは一言も言っていません。1段階ネストまでならこれで簡単に捌けます。

```php
<?php

$in = [
    ['2nd' => 'two', 'four' => '4th'],
    'three' => '3rd',
    ['one' => '1st'],
    '10th' => 'ten',
    ['6th' => 'six'],
    '5th' => 'five',
    'seven' => '7th',
    ['fourteen' => '14th', '11th' => 'eleven'],
    ['8th' => 'eight'],
    'thirteen' => '13th',
    '12th' => 'twelve',
    'nine' => '9th',
    ['15th' => 'fifteen'],
];

$out = array_replace(array_filter($in, 'is_scalar'), ...array_filter($in, 'is_array'));
echo json_encode($out, JSON_PRETTY_PRINT);
/*
さっきまでとは少し順番が違います
{
    "three": "3rd",
    "10th": "ten",
    "5th": "five",
    "seven": "7th",
    "thirteen": "13th",
    "12th": "twelve",
    "nine": "9th",
    "2nd": "two",
    "four": "4th",
    "one": "1st",
    "6th": "six",
    "fourteen": "14th",
    "11th": "eleven",
    "8th": "eight",
    "15th": "fifteen"
}
*/
```

配列だけを抜き取ったあと 1 段階平坦化して配列以外のものとくっつける，という方法です。

実は今回自分が最初に思いついたものがこれでした。いやー最初はこれ思いついたときキレイだなって思ったんですよ！でも `...` 使ったイテレータ展開の方法に長さで負けてたら立場がないわ，PHP 8.1 から強化されたの忘れてたわ🥺

### `foreach` による愚直なループ

説明不要。あんまりかっこよくないので，これを使った方は別の面で芸術点が欲しいところです（何の話だ）

## どのように `1st` `2nd` `3rd` のように数字付き省略形序数詞を判定するか

### 1文字目が数値文字かどうかを見る

初見で度肝を抜かれました。実務だと Uninitialized string offset エラーを引くリスクがあるからあんまり使いたくはないですね。

```php
<?php

var_dump(is_numeric('1st'[0])); // true
var_dump(is_numeric('first'[0])); // false

var_dump(ctype_digit('1st'[0])); // true
var_dump(ctype_digit('first'[0])); // false
```

`preg_match` を使っている方も多数いらっしゃいましたが，このへんは PHP に精通している人なら正規表現を使わずに捌く部分ですね。

### 整数型にキャストする

わりとこっちがオーソドックスなんじゃないかなと思います。 以下の説明中の `(bool)` キャストは省略してもいいです。

```php
<?php

var_dump((bool)(int)('1st')); // true
var_dump((bool)(int)('first')); // false

var_dump(boolval(intval('1st'))); // true
var_dump(boolval(intval('first'))); // false

var_dump((int)'1st' > 0); // true
var_dump((int)'first' > 0); // false

// var_dump('1st' > 0); // true
// var_dump('first' > 0); // ← PHP 8.0 以降と 7.4 までで動作が変わっています！要注意
```

**`string` と `int` の曖昧比較は<font color=red> PHP 8.0 で破壊的変更</font>が入ったので注意してください。**

### `ctype_alpha` の否定を使う

「全てがアルファベットではない」 → 「少なくとも数字が 1 つ以上含まれている」

```php
<?php

var_dump(!ctype_alpha('1st')); // true
var_dump(!ctype_alpha('first')); // false
```

今回に限りこういう方法も使えますね。

## どのように値とキーを反転させるか

### `array_walk_recursive` または `foreach` ループの中で if または三項演算子

最も愚直な方法。

```php
<?php

$in = [
    ['2nd' => 'two', 'four' => '4th'],
    'three' => '3rd',
    ['one' => '1st'],
    '10th' => 'ten',
    ['6th' => 'six'],
    '5th' => 'five',
    'seven' => '7th',
    ['fourteen' => '14th', '11th' => 'eleven'],
    ['8th' => 'eight'],
    'thirteen' => '13th',
    '12th' => 'twelve',
    'nine' => '9th',
    ['15th' => 'fifteen'],
];

$out = [];
array_walk_recursive($in, function ($value, $key) use (&$out) {
    if ((int)$value) {
        $out[$value] = $key;
    } else {
        $out[$key] = $value;
    }
});

echo json_encode($out, JSON_PRETTY_PRINT);
/*
{
    "2nd": "two",
    "4th": "four",
    "3rd": "three",
    "1st": "one",
    "10th": "ten",
    "6th": "six",
    "5th": "five",
    "7th": "seven",
    "14th": "fourteen",
    "11th": "eleven",
    "8th": "eight",
    "13th": "thirteen",
    "12th": "twelve",
    "9th": "nine",
    "15th": "fifteen"
}
*/
```

少しオシャレな書き方だと，こういうのもありました。

```php
$out = [];
array_walk_recursive($in, function ($value, $key) use (&$out) {
    (int)$value ? $out[$value] = $key : $out[$key] = $value;
});
```

```php
$out = [];
array_walk_recursive($in, function ($value, $key) use (&$out) {
    $out[(int)$value ? $value : $key] = (int)$value ? $key : $value;
});
```

```php
$out = [];
array_walk_recursive($in, function ($value, $key) use (&$out) {
    $out += (int)$value ? [$value => $key] : [$key => $value];
});
```

#### 亜種1: `min` `max` で比較する

https://twitter.com/akebi_mh/status/1568117648533389312

こちらは解答からピックアップ。初見でかなりびっくりしました。少し分かりやすいように書き下します。

```php
<?php

$in = [
    ['2nd' => 'two', 'four' => '4th'],
    'three' => '3rd',
    ['one' => '1st'],
    '10th' => 'ten',
    ['6th' => 'six'],
    '5th' => 'five',
    'seven' => '7th',
    ['fourteen' => '14th', '11th' => 'eleven'],
    ['8th' => 'eight'],
    'thirteen' => '13th',
    '12th' => 'twelve',
    'nine' => '9th',
    ['15th' => 'fifteen'],
];

$out = [];
array_walk_recursive($in, function (...$pair) use (&$out) {
    $out[min($pair)] = max($pair);
});

echo json_encode($out, JSON_PRETTY_PRINT);
/*
{
    "2nd": "two",
    "4th": "four",
    "3rd": "three",
    "1st": "one",
    "10th": "ten",
    "6th": "six",
    "5th": "five",
    "7th": "seven",
    "14th": "fourteen",
    "11th": "eleven",
    "8th": "eight",
    "13th": "thirteen",
    "12th": "twelve",
    "9th": "nine",
    "15th": "fifteen"
}
*/
```

なるほど， **数字がアルファベットよりも文字コードが若い** ことを利用しているんですね！これは賢い
ゴルフ専用なのでプロダクションでは使えませんが，なかなかエレガントだと思いました。

#### 亜種2: 引数を `sort` する

@tadsan 氏の解答自体はこの記事最後の大喜利部門で取り上げているのですが，他にも工夫点があって見落としていたので追記で紹介します。

https://twitter.com/tadsan/status/1570359185082306565


```php
<?php

$in = [
    ['2nd' => 'two', 'four' => '4th'],
    'three' => '3rd',
    ['one' => '1st'],
    '10th' => 'ten',
    ['6th' => 'six'],
    '5th' => 'five',
    'seven' => '7th',
    ['fourteen' => '14th', '11th' => 'eleven'],
    ['8th' => 'eight'],
    'thirteen' => '13th',
    '12th' => 'twelve',
    'nine' => '9th',
    ['15th' => 'fifteen'],
];

$out = [];
array_walk_recursive($in, function (...$pair) use (&$out) {
    sort($pair);
    $out[$pair[0]] = $pair[1];
});

echo json_encode($out, JSON_PRETTY_PRINT);
/*
{
    "2nd": "two",
    "4th": "four",
    "3rd": "three",
    "1st": "one",
    "10th": "ten",
    "6th": "six",
    "5th": "five",
    "7th": "seven",
    "14th": "fourteen",
    "11th": "eleven",
    "8th": "eight",
    "13th": "thirteen",
    "12th": "twelve",
    "9th": "nine",
    "15th": "fifteen"
}
*/
```

考え方は `min` `max` と同じですが，（最後のステップでソートを使うのに）こんなところでもソートが出てくるのが面白いですね。

### 平坦化済みの配列に対して `array_flip` を適用する

`array_flip` という関数はエントリ全体の反転を行ってくれます。それ故に，反転してほしいものだけをまとめて取り出して後から合成という手法を採ることができます。

```php
<?php
$x = [...new RecursiveIteratorIterator(new RecursiveArrayIterator([
    ['2nd' => 'two', 'four' => '4th'],
    'three' => '3rd',
    ['one' => '1st'],
    '10th' => 'ten',
    ['6th' => 'six'],
    '5th' => 'five',
    'seven' => '7th',
    ['fourteen' => '14th', '11th' => 'eleven'],
    ['8th' => 'eight'],
    'thirteen' => '13th',
    '12th' => 'twelve',
    'nine' => '9th',
    ['15th' => 'fifteen'],
]))];

// 値が 1st, 2nd, ... のものだけを取り出してキー反転
// 値が first, second, ... のものだけを取り出す
// これらを合成
$out = array_flip(array_filter($x, 'intval')) + array_filter($x, 'ctype_alpha');

echo json_encode($out, JSON_PRETTY_PRINT);
/*
{
    "4th": "four",
    "3rd": "three",
    "1st": "one",
    "7th": "seven",
    "14th": "fourteen",
    "13th": "thirteen",
    "9th": "nine",
    "2nd": "two",
    "10th": "ten",
    "6th": "six",
    "5th": "five",
    "11th": "eleven",
    "8th": "eight",
    "12th": "twelve",
    "15th": "fifteen"
}
*/
```

## どのようにソートさせるか

### `ksort` で `SORT_REGULAR` `SORT_NATURAL` を指定

PHP のソート関数，めちゃくちゃ大量にあって選ぶのに困りますが， ちょうど `ksort()` がキーを基準としてキーバリューペアをソートする関数になります。しかし，そのままでは **`10th` 以上の値の順序がおかしくなってしまいます。** 文字列では `"1" "10" "2"` という順序になるためです。

```php
<?php

$x = [...new RecursiveIteratorIterator(new RecursiveArrayIterator([
    ['2nd' => 'two', 'four' => '4th'],
    'three' => '3rd',
    ['one' => '1st'],
    '10th' => 'ten',
    ['6th' => 'six'],
    '5th' => 'five',
    'seven' => '7th',
    ['fourteen' => '14th', '11th' => 'eleven'],
    ['8th' => 'eight'],
    'thirteen' => '13th',
    '12th' => 'twelve',
    'nine' => '9th',
    ['15th' => 'fifteen'],
]))];
$out = array_flip(array_filter($x, 'intval')) + array_filter($x, 'ctype_alpha');

ksort($out);
echo json_encode($out, JSON_PRETTY_PRINT);
/*
{
    "10th": "ten",
    "11th": "eleven",
    "12th": "twelve",
    "13th": "thirteen",
    "14th": "fourteen",
    "15th": "fifteen",
    "1st": "one",
    "2nd": "two",
    "3rd": "three",
    "4th": "four",
    "5th": "five",
    "6th": "six",
    "7th": "seven",
    "8th": "eight",
    "9th": "nine"
}
*/
```

そこで， `SORT_NUMERIC` `SORT_NATURAL` いずれかのフラグをつけると比較方法を変えることができ，この問題に対処できます。

| フラグ | 方式 |
|:---|:---|
| `SORT_NUMERIC` | `(int)` キャストされた状態でソート |
| `SORT_NATURAL` | `strnatcmp` の自然順比較でソート |

```php
<?php

$x = [...new RecursiveIteratorIterator(new RecursiveArrayIterator([
    ['2nd' => 'two', 'four' => '4th'],
    'three' => '3rd',
    ['one' => '1st'],
    '10th' => 'ten',
    ['6th' => 'six'],
    '5th' => 'five',
    'seven' => '7th',
    ['fourteen' => '14th', '11th' => 'eleven'],
    ['8th' => 'eight'],
    'thirteen' => '13th',
    '12th' => 'twelve',
    'nine' => '9th',
    ['15th' => 'fifteen'],
]))];
$out = array_flip(array_filter($x, 'intval')) + array_filter($x, 'ctype_alpha');

ksort($out, SORT_NUMERIC);
echo json_encode($out, JSON_PRETTY_PRINT);

ksort($out, SORT_NATURAL);
echo json_encode($out, JSON_PRETTY_PRINT);

/*
{
    "1st": "one",
    "2nd": "two",
    "3rd": "three",
    "4th": "four",
    "5th": "five",
    "6th": "six",
    "7th": "seven",
    "8th": "eight",
    "9th": "nine",
    "10th": "ten",
    "11th": "eleven",
    "12th": "twelve",
    "13th": "thirteen",
    "14th": "fourteen",
    "15th": "fifteen"
}
*/
```

ほか， `uksort` でコールバック関数として `"strnatcmp"` を指定する方法もあります。 `SORT_NATURAL` を使った方法と動作的には全く同じです。

```php
uksort($out, 'strnatcmp');
```

# 解答紹介

模範解答以外は大喜利メインでいきます。

### 問題作成者推奨解答

```php
$x = [...new RecursiveIteratorIterator(new RecursiveArrayIterator($in))];
$out = array_flip(array_filter($x, 'intval')) + array_filter($x, 'ctype_alpha');
ksort($out, SORT_NATURAL);
```

https://3v4l.org/NpLC6

### 一般的部門 （+大喜利になりきれなかった部門）

https://twitter.com/_remew_/status/1567740342702862336

愚直な考え方も大事です

https://twitter.com/MadaraNari/status/1567740937815859200

1行に押し込めばいいって問題じゃないよ！

https://twitter.com/casheeeewnuts/status/1567743783080706048

上に同じ。 `ctype_alpha` に気づいたところはいいね！

https://twitter.com/kb10uy/status/1567748813531795457

`array_walk_recursive` 部門なら模範解答

https://twitter.com/mihoshiinfo/status/1567780868797911042

配列で `+=` 操作してくれる人好きです
[配列結合演算子, array_merge, array_replace を徹底比較 - Qiita](https://qiita.com/mpyw/items/578e1a14879e679d2141)

https://twitter.com/kiyoami/status/1567847757263835137

https://twitter.com/yosida001/status/1567785745838129152

```php
$iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($in));

$tmp = array_fill(1, iterator_count($iterator), "");
foreach($iterator as $key => $value) {
    if (preg_match("/^([0-9]+)/", $key, $match) === 1) {
        $index = $match[1];
        $counter = $key;
        $number = $value;
    } else {
        preg_match("/^([0-9]+)/", $value, $match);
        $index = $match[1];
        $counter = $value;
        $number = $key;
    }
    
    $tmp[$index] = [$counter => $number];
}

$result = array_reduce($tmp, "array_merge", []);
var_dump($result);
```

こういうの**バケツソート**って言うんですよね

https://twitter.com/d_hori_web/status/1567809691597815810

でぃーほりさんが初めて `array_flip` 使った解答出してくれたので嬉しかった

https://twitter.com/n_1215/status/1567887722794352640

https://twitter.com/akebi_mh/status/1567954133197651968

`array_walk_recursive` を限界まで削った形

https://twitter.com/nullbytep/status/1567882839882072067

読みにくいけどやってることは普通なので一般部門！ `array_reduce` 使った解答はこれが初観測

https://twitter.com/tadsan/status/1567832561531125760

`match` 式は好きです

https://twitter.com/nojimage/status/1568103067807264768

```php
$it = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($in));
$flatNum = iterator_to_array(new \RegexIterator($it, '/^\d/'));
$flatAlpha = iterator_to_array(new \RegexIterator($it, '/^[^\d]/'));
$out = array_merge(array_flip($flatNum), $flatAlpha);
ksort($out, SORT_NATURAL);
var_dump($out);
```

`RegexIterator` に芸術点を加算

### 大喜利部門

https://twitter.com/chiroruxxxx/status/1567771268354813952

モダン PHP をぶっ壊す！！！

https://twitter.com/tamu_cola/status/1567766180211077120

唐突な `strtotime` 見たとき腹抱えて笑いました。わざわざ序数詞を日付にしなくてもどうにかなるよｗ

https://twitter.com/n42k1jp/status/1567774867562590209

https://twitter.com/KentarouTakeda/status/1567847672635342849

こういう問題出すとソースコードコメント解析して解答を eval 錬成するマン絶対おるんよ

https://twitter.com/ikasandesu/status/1567776490582081536

ドMかな？

https://twitter.com/nsfisis/status/1568541619443617792

```php
$ys = [];
foreach ($in as $k => $xs)
  if ([] < $xs)
    foreach ($xs as $l => $x)
      $ys[(int)[$x, $l][$l < $x]] = [[$x, $l], [$l, $x]][$l < $x];
  else
    $ys[(int)[$xs, $k][$k < $xs]] = [[$xs, $k], [$k, $xs]][$k < $xs];
$zs = [];
for ($i = true; $ys[$i] ?? false; $i += true)
  $zs[$ys[$i][false]] = $ys[$i][true];

echo "[\n";
foreach ($zs as $k => $z) {
  echo "    '{$k}' => '{$z}',\n";
}
echo "]\n";
```

別方面のドM。これはすごい。 **関数コールも数値リテラルも 1 つもないようです。** これは PHP を熟知していないと出来ない技。

https://twitter.com/chiroruxxxx/status/1567781603514138629

「`$in` を使って」の条件は満たしているので合格です

https://twitter.com/tarupachi/status/1567789781584855044

https://twitter.com/devhi9a/status/1569694790903791617

https://twitter.com/akebi_mh/status/1567838271438462976

https://twitter.com/takayuki_h/status/1567870692930240512

https://twitter.com/ttskch/status/1567877825323237382

全部 `json_encode()` してパースマンが数人居ました。 `json_decode()` 職人してる人は加点します

https://twitter.com/akebi_mh/status/1568356089741344768

```php
preg_match_all('/"(\d+)\w+"/', $json = json_encode($in), $m);
$out = [];
$date = new DateTimeImmutable;
for($i = max(1, min($m[1])), $max = min(31, max($m[1])); $i <= $max; $i++) {
  $key = $date->setDate(2022, 1, $i)->format('jS');
  if(preg_match('/("(\w+)":)?"'.$key.'"(:"(\w+)")?/', $json, $m) && $value = $m[2] ?: $m[4]) {
    $out[$key] = $value;
  }
}
print_r($out);
```

JSON + 日付職人の合わせ技。これはすごい

https://twitter.com/ttskch/status/1567846848634961922


`ob_start()` + `ob_get_clean()`，この上ないぐらい PHP らしくて好き

https://twitter.com/ad5jp/status/1568369105442590720

こちらは `var_export()` 派

https://twitter.com/hojuballoon/status/1568098034101415936

`http_build_query()` 派

https://twitter.com/m3m0r7/status/1567805733307297792

ごめん読めない

https://twitter.com/takaram71/status/1567972438537019392

配列と可変長引数の交換が忙しすぎる

https://twitter.com/shztmk/status/1567822360706961409

`SplPriorityQueue`！久しぶりに名前聞いたな

https://twitter.com/you_r_name/status/1567949291943239681

シェル芸を我慢できなかった人

https://twitter.com/tadsan/status/1567883771126644744

こちらもただのシェル芸…かと思ったら，よく見たら **スリープソート** の実装でした。プロセス開いてるほうがインパクト強すぎて最初気づかなかったｗ

PHP はプロセス開かないと JavaScript みたいな遅延処理を実現できないんだなぁ…

https://twitter.com/tyabu12/status/1567904347299917824

**乱数のシードをわざわざ見つけてきた人。** これが一番びっくりした

https://twitter.com/bufferings/status/1568430001225367554

https://qiita.com/rana_kualu/items/19040b3cad642368196a

**`$in` をどっかに忘れてきた人たち。 @rana_kualu さんのはさすがに草**

### 職場部門

https://twitter.com/d_hori_web/status/1567727134285918210

https://twitter.com/0DivideError/status/1567785201778196480

# 表彰

## 優勝

**[@akebi_mh](https://twitter.com/akebi_mh) さん**

めっちゃいっぱい回答してくれて感激です。 `min()` `max()` の交換が目からウロコでした。

## 準優勝（追加）

**[@tadsan](https://twitter.com/tadsan) さん**

せっかくスリープソートで実装してくれたので追加で表彰します！
（最初気づかなくてすみません

## ナイスゴルフ賞

**@rana_kualu さん**

ゴルフといえばこの方の印象。問題文読んでない人他にもたくさんいたので細かいことは気にしないです（気にしろよ）

## ナイスアルゴリズム賞

**[@tyabu12](https://twitter.com/tyabu12) さん**

乱数調整に度肝を抜かれました。

## PHP エキスパート賞（追加）

**[@nsfisis](https://twitter.com/nsfisis) さん**

難易度の高い縛りプレイに拍手。
難易度高いなぁと改めて思ったので追加しました！