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.11 23 4No.2: 2 14 3No.3:2 41 3No.44 2 3 1No.54 3 2 1No.63 41 2No.71 32 4N0.83 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## 使用numpydef 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之类,还是直接用库吧。
完整源码
最后附上完整的代码: