python3中二维List数据的三种处理方法及比较
标签: python 矩阵 算法
[TOC]
问题引入
这几天在处理一个棋盘状态数据,需要对棋盘状态状态是否为“同一个状态”,这里就需要对棋盘状态进行旋转,左右翻转等操作。一个棋盘总共可以旋转:0度,90度,180度,270度4种;每种旋转后还可以左右翻转2种,总共有4x2=8种状态。为了方便,需要先用python把这8种状态表示出来,于是引出了题目的问题:在python里如何对矩阵进行变化,这里的变化指旋转和左右翻转等。
这里使用的版本是python3.6
原始数据
为了简便,使用一个最简单的数据来模拟:一个2X2的棋盘用List来保存下数据
lstDat = [
[1,2],
[3,4],
]
期望的最终结果有8个,分别是这样的: 其中1,3,5,7 分别是旋转0度,90度,180度,270度; 2、4、6、8 分钟是1、3、5、7进行左右翻转得到的结果。
NO.1
1 2
3 4
No.2:
2 1
4 3
No.3:
2 4
1 3
No.4
4 2
3 1
No.5
4 3
2 1
No.6
3 4
1 2
No.7
1 3
2 4
N0.8
3 1
4 2
对于矩阵的处理有很多,但在这里只需要用到两种:
旋转90度(顺时针,逆时针都可以)
左右翻转
所以最终问题转变为如何实现对List表示的二维矩阵进行上述的两种操作。
使用列表生成式
列表生成式就是使用以下的方式来遍历生成一个新的表列: [ 变量表达式 for 变量 in 表达式 ] 当然是循环是可以嵌套的。
#---------------------------------------
## 使用列表生成式
def listGen (lstDat):
#transpose
print('-'* 30)
print ('转置矩阵:')
tp = [[row[i] for row in lstDat ] for i in range(len(lstDat[0]))]
for item in tp: print (item)
print('-'* 30)
#逆时针转90度
print ('逆时针转90度:')
rt90 = [[row[i] for row in lstDat ] for i in range(len(lstDat[0])-1,-1,-1) ]
for item in rt90: print (item)
print('-'* 30)
#顺时针转90度
print ('顺时针转90度:')
rt90 = [[lstDat[j][i] for j in range(len(lstDat)-1,-1,-1) ] for i in range(len(lstDat[0]))]
for item in rt90: print (item)
print('-'* 30)
print ('左右翻转:')
flip = [[row[i] for i in range(len(row)-1,-1,-1) ] for row in lstDat]
for item in flip: print (item)
运行结果:
---------- python36 ----------
原始数据:
[1, 2]
[3, 4]
使用列表生成器:
------------------------------
转置矩阵:
[1, 3]
[2, 4]
------------------------------
逆时针转90度:
[2, 4]
[1, 3]
------------------------------
顺时针转90度:
[3, 1]
[4, 2]
------------------------------
左右翻转:
[2, 1]
[4, 3]
输出完成 (耗时: 0 秒)
使用map + zip
使用map可以方便对矩阵进行转置,也就是把(行,列)变成 (列,行)的方式。对于旋转是有直接的方法的,但是左右翻转没有,所以需要先逆时针旋转90度,再进行转置。
def mapzip (lstDat):
print('-'* 30)
print ('转置矩阵:')
matrix = lstDat.copy()
matrix[:] = map(list,zip(*matrix))
for item in matrix: print (item)
#顺时针转90度
print ('顺时针转90度:')
matrix = lstDat.copy()
matrix[:] = map(list,zip(*matrix[::-1]))
for item in matrix: print (item)
#逆时针转90度
print ('逆时针转90度:')
matrix = lstDat.copy()
matrix[:] = map(list,zip(*matrix))
matrix[:] = matrix[::-1]
for item in matrix: print (item)
#左右翻转
print ('左右翻转:')
matrix = lstDat.copy()
matrix[:] = map(list,zip(*matrix))
matrix[:] = matrix[::-1]
matrix[:] = map(list,zip(*matrix))
for item in matrix: print (item)
运行结果:
---------- python36 ----------
原始数据:
[1, 2]
[3, 4]
==============================
使用Map+Zip:
------------------------------
转置矩阵:
[1, 3]
[2, 4]
顺时针转90度:
[3, 1]
[4, 2]
逆时针转90度:
[2, 4]
[1, 3]
左右翻转:
[2, 1]
[4, 3]
输出完成 (耗时: 0 秒)
使用numpy
最后一种方法就是直接用现成的库了,numpy提供了丰富的方法,这里只需要用到两个就够了。与map的方式相同,对于旋转是有直接的方法的,但是左右翻转没有,所以也需要先逆时针旋转90度,再进行转置。
import numpy
## 使用numpy
def usenumpy (lstDat):
nd = numpy.array(lstDat)
#逆时针转90度:
print ('逆时针转90度:')
nd1 = numpy.rot90(nd)
print (nd1)
print ('顺时针转90度:')
nd1 = numpy.rot90(nd,k = -1)
print (nd1)
print ('左右翻转:')
nd1 = numpy.rot90(nd)
nd1 = numpy.transpose(nd1)
print (nd1)
运行结果
---------- python36 ----------
原始数据:
[1, 2]
[3, 4]
==============================
使用numpy:
逆时针转90度:
[[2 4]
[1 3]]
顺时针转90度:
[[3 1]
[4 2]]
左右翻转:
[[2 1]
[4 3]]
输出完成 (耗时: 0 秒)
得到结果
研究了那么多种旋转,左右翻转的方式,最终还是为了得到8种状态,这里就用numpy方式来调用实现。
import numpy
## 输出所有状态
def getstatus (lstDat):
nd = numpy.array(lstDat)
index = 0
for i in range (4) :
index +=1
print('-'* 10 + str(index) + '-' * 10)
print (nd)
#
#print (','.join([str(y) for x in nd.tolist() for y in x]))
index +=1
print('-'* 10 + str(index) + '-' * 10)
nd2 = numpy.rot90(nd) #,k = -1,axes=(1, 0))
nd2 = numpy.transpose(nd2)
print (nd2)
#print (','.join([str(y) for x in nd2.tolist() for y in x]))
nd = numpy.rot90(nd)
运行结果:
---------- python36 ----------
原始数据:
[1, 2]
[3, 4]
==============================
输出所有状态:
----------1----------
[[1 2]
[3 4]]
----------2----------
[[2 1]
[4 3]]
----------3----------
[[2 4]
[1 3]]
----------4----------
[[4 2]
[3 1]]
----------5----------
[[4 3]
[2 1]]
----------6----------
[[3 4]
[1 2]]
----------7----------
[[3 1]
[4 2]]
----------8----------
[[1 3]
[2 4]]
输出完成 (耗时: 0 秒)
分析对比
三种思路的对比: 1.列表生成器。感觉这个比较传统,还是老思路,一个个去循环。作为练手可以用用。 2. 使用map 具有py的新思维,语句也比较简洁,建议要熟悉这种方式。 3. 使用numpy。 如果是大规模的数据,涉及到大量计算,比如ML,DL之类,还是直接用库吧。
完整源码
最后附上完整的代码: 完整源码