最近はpython3にハマってまして(;´Д`)

ここは私のお気に入りメモの場所なので好きな事を書くのです(`・ω・´)

検索してもなかなか斜め方向へのアクセスのいい方法は見つけられなかったのと

いつも検索して助けられている部分もあるのでもしかしたら最果てのこの場所で

探しているものが見つかったなら・・・と思ってメモを記すことにしました。

python3はpaizaラーニングというサイトで入門編をさらっとやってから問題集で

勉強した感じです。Cランクの問題集が終わったのでBランク問題へ。

同ランクでも難易度にだいぶ幅があるので( ノД`)スキルチェックする時は

難易度をよく見てから受けましょう(失敗したら失敗したコードが残っちゃうので)

Cランク受ける時もBランク受ける時も失敗続きでへこみます(´・ω・`)

問題集も答えを提出してからじゃないと模範解答とかみれないので

一度は自分で考えるけどあまりにもわからなければ時間ももったいないので

適当に提出して方針と模範解答から学ぶのも一つの手としております。


この2次配列の縦横斜めの操作もBランク問題ででてくるものです。

2次元配列とは文字道理2D・・配列が縦×横(平方)になっている配列のことです。

2D地図とかピクセルとか・・・そういったものの操作に用いられる様です。



# coding: utf-8
h=4
w=5
a=[[0]*w for _ in range(h)]
for i in range(h):
    c=0
    for j in range(w):
        a[i][j]=str(i)+str(c)
        c+=1
print(a)      
for i in a:
    print(" ".join(i))

[['00', '01', '02', '03', '04'], ['10', '11', '12', '13', '14'], ['20', '21', '22', '23', '24'], ['30', '31', '32', '33', '34']]

4行5列の2次配列だと普通は上のように表示されますが

 00 01 02 03 04

 10 11 12 13 14

 20 21 22 23 24 

 30 31 32 33 34

縦横をそろえて表示するとこうなります。

配列は0番から始まるので00がa[0][0]、34がa[3][4]を示しています。

2次配列を操作する場合大抵は2重ループで取り回します。

for i で行を for jで列を回しています。

これが配列の横向き(1行ずつ)の操作となります。

for i で列をfor jで行をまわすと

配列の縦向き(1列ずつ)の操作となります。

では斜めはどうするのかというと

斜めは操作を2回に分けます。対角線上に線引きして

三角形を2つにしてひとつづつ取りまわすイメージです。





# coding: utf-8
h=4 #行
w=5 #列
a=[[0]*w for _ in range(h)] #2次配列の宣言と空の要素を入れる
c=1 #1からの連番にするため
for i in range(h): #行を回す
    for j in range(w): #列を回す
        a[i][j]=c #a[0][0]]なら1を再代入a[3][4]なら20を再代入
        c+=1 #カウントを1つずつ増やす

#2次配列aを半角スペース区切りで出力
for i in range(h):
    for j in range(w):
        if j<w-1
            print(a[i][j],end=" ")
        else:
            print(a[i][j])







# coding: utf-8
h=4 #行
w=5 #列
a=[[0]*w for _ in range(h)] #2次配列の宣言と空の要素を入れる
c=1 #1からの連番にするため
for i in range(w): #列を回す
    for j in range(h): #行を回す
        a[j][i]=c #a[0][1]]なら22を再代入a[0][3]なら4を再代入
        c+=1 #カウントを1つずつ増やす34

#2次配列aを半角スペース区切りで出力
for i in range(h):
    for j in range(w):
        if jj<w-1:
            print(a[i][j],end=" ")
        else:
            print(a[i][j])

斜め(上方向)











行の数値が0,1,2,3と一つずつ増えているのと列の数値も1ずつ増えている。

外側のループを行の長さでまわす

内側のループは1回2回3回・・と1回ずつ増やした回数で列でまわす。

1回ずつ増やして列の長さを超えるとエラーになるので列の長さを超えないようにする。

外側のループ変数 i が0の時は iに1を足した 1に  iが1の時は1を足して

2にと i +1 とする そして列の長さを超えないように 列の長さと比べて

i +1が小さいうちは i+1を i+1がれつより大きければ列の長さにする。

ループのレンジを min(i+1, w)とする。

今回の例だと行の長さの方が短いから列の長さを超えないが

行の長さが列よりも大きいと列の長さを超えるので色々なパターンを

考えて設定する。

a[行番=i][列番=j]  a[2][0] a[1][1] a[0][2] を見たときに

行が iが i-j 列が jとなっていることがわかる。

iが2の時 行番が 2-0 2-1 2-2となっている 上方向に行が移動するので

行番を1ずつ小さくしている。

列はjが0~1ずつ増えていくので列番はjとする



# coding: utf-8

h=4 #行

w=5 #列

a=[[0]*w for _ in range(h)] 

c=1 

for i in range(h):

    for j in range(min(i+1,w)):

        a[i-j][j]=c

        c+=1 



#2次配列aを半角スペース区切りで出力

for i in range(h):

    for j in range(w):

        if j<w-1:

            print(a[i][j],end=" ")

        else:

            print(a[i][j])



出力すると

1 3 6 10 0
2 5 9 0 0
4 8 0 0 0
7 0 0 0 0 と斜め左上半分だけ埋まりましたね・・・
こんなのだれが思いつくというのでしょうね・・・(-_-;)
この問題の前の斜めの問題でも斜めは分けていたのでなんとなくは
やり方がわかってたけどrangeのmin()も前の問題でなんとなく・・
ここのrangeの部分がpython3は自由すぎるくらい
に設定できるところも面白いところの一つです。
配列のアドレスからiをひいたり足したり・・・ややこしい(´・ω・`)
この問題はpython3の模範解答は無いのでc++かjavaでの模範解答から
python3に落とし込む必要がありました。
一つ一つ手を動かして~とか行と列の長さを超えないようにとかしか
ヒントもなくてわかるか~(/・ω・)/となるのが普通だと思う。



列番号が1から始まっているのと行の一番下から斜め上にあがってる。
行番号は1ずつ減り列番号は1~1ずつ増えます。
ここで大事なのは列番号が0になることはないことと行番号の範囲を超えないこと。
外側のループは列の1から初めて5になるまでの4回なのでrange(1,w)
内側のループは4回3回2回1回と一つずつ減っていく仕様に、行の長さよりも列が
大きい場合は行の長さをこえるので最大回転数を行の長さに行の長さを下回る場合は
w-iにしてひとつずつ減らしていく。range(min(h,w-i))
a[行][列] a[3][1] a[2][2]a[1][3]a[0][4] 行の長さここでは4から(1+j)を引く
列はiが1から始まっていることとjが0からはじまっているのでi+jとして
1ずつ増やしていく。
for i in range(1,w):
        for j in range(min(h,w-i)):
            a[h-1-j][i+j]=c
            c+=1
これを先ほどの上半分とあわせる。




# coding: utf-8
h=4 #行
w=5 #列
a=[[0]*w for _ in range(h)] 
c=1 
for i in range(h):
        for j in range(min(i+1,w)):
            a[i-j][j]=c
            c+=1
for i in range(1,w):
        for j in range(min(h,w-i)):
            a[h-1-j][i+j]=c
            c+=1


#2次配列aを半角スペース区切りで出力
for i in range(h):
    for j in range(w):
        if j<w-1:
            print(a[i][j],end=" ")
        else:
            print(a[i][j])

1 3 6 10 14 

2 5 9 13 17 

4 8 12 16 19 

7 11 15 18 20 と出力されます。


最後に逆方向の斜め

斜め(左下方向)











さっきののと反対なだけなので最初に斜めにする処理の仕方が

解っているなら簡単です。

上半分は

外側のループを列でまわす 内側のループを行の長さか i+1の小さい方でまわす

a[j][i-j]とする a[0][0-0]   a[0][1-0]a[1][1-1].....となる。


下半分は

外側を行でまわす。内側を行の長さか h-i の小さい方で回す

a[i+j][w-1-j]とする a[0+0][5-1-0]a[0+1][5-1-1]...となる。


# coding: utf-8
h=4 #行
w=5 #列
a=[[0]*w for _ in range(h)] 
c=1 
for i in range(w):
        for j in range(min(i+1,h)):
            a[j][i-j]=c
            c+=1
for i in range(1,h):
        for j in range(min(h-i,w)):
            a[i+j][w-1-j]=c
            c+=1


#2次配列aを半角スペース区切りで出力
for i in range(h):
    for j in range(w):
        if j<w-1:
            print(a[i][j],end=" ")
        else:
            print(a[i][j])
1 2 4 7 11
3 5 8 12 15
6 9 13 16 18 
10 14 17 19 20となるはず~ 
標準入力から数字を与えられるパターンで
1から連番で数字を割り振っていく↓


# coding: utf-8
h,w,d=map(int,input().split())
a=[[0]*w for _ in range(h)]
c=1

if d==1:
   
    for i in range(h):
        for j in range(min(i+1,w)):
            a[i-j][j]=c
            c+=1
    for i in range(1,w):
        for j in range(min(h,w-i)):
            a[h-1-j][i+j]=c
            c+=1

elif d==2:
    
    for i in range(h):
        for j in range(w):
            a[i][j]=c
            c+=1

elif d==3:
    
    for i in range(w):
        for j in range(h):
            a[j][i]=c
            c+=1

else:
   
    for i in range(w):
        for j in range(min(i+1,h)):
            a[j][i-j]=c
            c+=1
    for i in range(1,h):
        for j in range(min(h-i,w)):
            a[i+j][w-1-j]=c
            c+=1
    

for i in range(h):
    for j in range(w):
        if j<w-1:
            print(a[i][j],end=" ")
        else:
            print(a[i][j])



1なら斜め右上2なら横・・・。

これで完成です(`・ω・´)