Back to home

一维数组转二维数组

起因

手头碰到一段代码需要重构,打开脚本之后发现代码如下:

def list_splist(lists):
    listLen = 0
    newList = []
    if len(lists) % 3 == 0:
        listLen = len(lists) / 3
    else:
        listLen = len(lists) / 3 + 1
    for i in range(0,listLen):
        lis = []
        try:  
            lis.append(lists[i*3])
        except:
            err = "do not care!"
        try:  
            lis.append(lists[i*3+1])
        except:
            err = "do not care!"
        try:  
            lis.append(lists[i*3+2])
        except:
            err = "do not care!"
        newList.append(lis)
    return newList

简而言之就是将一段数组取出来,拆成行长度一定的二位数组.但是明显有很多吐槽的地方.

  • 二十三行Python代码.
  • 四个临时变量(listLen,newList,err,lis).
  • 一个for循环,三个try…except.

拿Python写八股呢? 好在前人不在,并且架构随我定制,于是可以在不兼容原有风格的优势下,尽可能的对代码进行整改.

思考

原谅我的不深入,如果就因为这二十三行八股而大费周章确实不值得,节约时间.
切分一维数组到二维的问题核心是已知一维数组长度的情况下,二维数组的长度到底该是多少? 再由于数组长度余数的部分需要保留,我们只需要保证向上取整即可,而Python默认是向下取整的,也就是说单纯的整数相除,小数点后的都会被舍弃,无论值是多少. 这有别于C中的向0取整.

当然我们也有众多工具.比如math包中的math.ceil方法可以对浮点数进行向上取整,但他需要是浮点数,且还是一次方法的调用.

通用向上取整

向上取整用UP来表示.

  • 假设A>1, B>1, A,B都是整数. 设A = NB + M ,其中N为非负数,M为0~B-1的数.
  • 则有 A/B = N + M/B
  • 凑项得 (A+B-1)/B = N + 1 + (M-1)/B
  • if M == 0 => UP(A/B) = N , int((A+B-1)/B)=N+int(1-1/B)=N
  • if M >=1 || M <= (B-1) , 0 <= M-1 <= B-2 => UP(A/B)=N+1, int((A+B-1)/B)=N+1+int((M-1)/B)=N+1
  • 所以对于A>1,B>1的所有整数都有: UP(A/B)=int((A+B-1)/B)

应用

工欲善其事,必先利其器.接下来我们可以流畅的写出如下切割一维数组的方法,加上极具Python意义的列表推导,生成器,这一切都使得问题变得异常简单.

lists = [lists[i*ROWLEN:(i+1)*ROWLEN] for i in xrange((len(lists)+ROWLEN-1)/ROWLEN)]

您是否也觉得,在code前,准备适当的时间来思考,能够事半功倍呢?

更新

2013-06-26

其实用 iter 更简便

In [1]: d = iter("abc"*5)
In [2]: [list(islice(d, 4)) for i in xrange(4)]
Out[2]:
[['a', 'b', 'c', 'a'],
 ['b', 'c', 'a', 'b'],
 ['c', 'a', 'b', 'c'],
 ['a', 'b', 'c']]