Posted at

ずんだの菱形アルファベット問題 Python3 & SQL編

もとねた: ずんだの菱形アルファベット問題 Ruby編

Python3で、まずは「ふつう」に回答してみました。もとねたでは実行時引数を読み込んでいましたが、以下の解答では標準入力の1行目をnとしています。

def draw(n):

if n % 2 == 0:
return 'invalid'

mid = n // 2
matrix = [['_'] * n for _ in range(n)]
for x, alphabet in zip(range(n), 'abcdefghijklmnopqrstuvwxyz'):
y = abs(mid - x) - mid
matrix[x][mid + y] = matrix[x][mid - y] = alphabet

return '\n'.join(''.join(row) for row in matrix)

if __name__ == '__main__':
n = int(input())
print(draw(n))

次はPython3の「ふつう」ではない解答、つまり1行野郎で解いたものが以下になります。これも「ふつう」の解答と同様に標準入力の1行目をnとします。

print((lambda n : 'invalid' if n % 2 == 0 else '\n'.join(''.join(ch if y in (abs(n // 2 - x), (n - 1) - abs(n // 2 - x)) else '_' for y in range(n)) for x, ch in zip(range(n), 'abcdefghijklmnopqrstuvwxyz')))(int(input())))

たとえばPython3のREPLなどをつかって、上記の1行野郎を実行してみると、想定通りの結果が得られることがわかります。

$ python3

Python 3.6.5 (default, Apr 1 2018, 05:46:30)
[GCC 7.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print((lambda n : 'invalid' if n % 2 == 0 else '\n'.join(''.join(ch if y in (abs(n // 2 - x), (n - 1) - abs(n // 2 - x)) else '_' for y in range(n)) for x, ch in zip(range(n), 'abcdefghijklmnopqrstuvwxyz')))(int(input())))
5
__a__
_b_b_
c___c
_d_d_
__e__
>>> print((lambda n : 'invalid' if n % 2 == 0 else '\n'.join(''.join(ch if y in (abs(n // 2 - x), (n - 1) - abs(n // 2 - x)) else '_' for y in range(n)) for x, ch in zip(range(n), 'abcdefghijklmnopqrstuvwxyz')))(int(input())))
2
invalid


Python3だけではさみしいのでSQLでも解答してみました。以下がその解答になります。

入力はバインド変数:Nとして1から25までの整数を与えます。動作確認にはPostgreSQL 10.5を利用していますが、言語依存の機能はさほど利用していないので、多少の読み替えなどはあったとしても、基本的にはほかのDBMSでも動く--はず(´・ω・`)

WITH 

RECURSIVE alphabets(x, alphabet, list) AS (
SELECT -1, NULL, 'abcdefghijklmnopqrstuvwxyz'
UNION ALL
SELECT
x + 1,
SUBSTRING(list FROM 1 FOR 1),
SUBSTRING(list FROM 2)
FROM alphabets
WHERE LENGTH(list) > 0
),
rows(x, row) AS (
SELECT
a1.x,
STRING_AGG (
CASE WHEN a2.x IN (ABS(:N / 2 - a1.x), ABS(:N - 1 - ABS(:N / 2 - a1.x))) THEN a1.alphabet ELSE '_' END,
''
ORDER BY a2.x
)
FROM alphabets a1 CROSS JOIN alphabets a2
WHERE 0 <= a1.x AND a1.x < :N
AND 0 <= a2.x AND a2.x < :N
GROUP BY a1.x
)
SELECT
CASE WHEN :N % 2 = 0 THEN 'invalid' ELSE STRING_AGG(row, chr(10) ORDER BY x) END AS answer
FROM rows

このSQLをファイルzunda.sqlに保存し、たとえば以下のようにして実行します。psqlコマンドでは-vオプションを使って、バインド変数に値を設定することができるので、これを利用しています。

$ psql -d sandbox -U postgres -v N=24 -f zunda.sql

answer
---------
invalid
(1 row)

$ psql -d sandbox -U postgres -v N=25 -f zunda.sql
answer
---------------------------
____________a____________+
___________b_b___________+
__________c___c__________+
_________d_____d_________+
________e_______e________+
_______f_________f_______+
______g___________g______+
_____h_____________h_____+
____i_______________i____+
___j_________________j___+
__k___________________k__+
_l_____________________l_+
m_______________________m+
_n_____________________n_+
__o___________________o__+
___p_________________p___+
____q_______________q____+
_____r_____________r_____+
______s___________s______+
_______t_________t_______+
________u_______u________+
_________v_____v_________+
__________w___w__________+
___________x_x___________+
____________y____________
(1 row)