2016-02-13 86 views
2

使用Matlab一段時間後,我越來越喜歡它的sprintf函數,這是矢量化(矢量化是問題的關鍵部分)。Matlab的矢量化sprintf像python函數

假設一個具有列表li=[1,2,3,4,5,6]

sprintf("%d %d %d\n", li) 

將適用的格式上的元素在li彼此返回

"1 2 3\n4 5 6\n" 

爲字符串之後。

我目前的解決方案不罷工很Python的:

def my_sprintf(formatstr, args): 

    #number of arguments for format string: 
    n=formatstr.count('%') 

    res="" 

    #if there are k*n+m elements in the list, leave the last m out 
    for i in range(n,len(args)+1,n): 
     res+=formatstr%tuple(args[i-n:i]) 

    return res 

什麼是在Python做它的通常/更好的辦法?

有沒有可能,但沒有明確的格式字符串(n=formatstr.count('%')感覺就像一個黑客)引發預期參數的數量?

PS:爲了簡單起見可以假設的是,在該列表中的元素的數量是在格式字符串參數數量的倍數。

+0

你必須使用一個格式字符串? –

+0

@Padraic坎寧安:沒有,用的String.Format)的新版本(也未嘗不可。 – ead

+0

如果你想要一個強大的解決方案,我會傾向於將邏輯封裝在一個類中,子類string.Formatter –

回答

0

您可能需要刪除在該+= for循環。以下版本比您的版本快三倍。它也可以甚至在你要打印的%符號輸出的情況。因此,格式字符串包含'%%'。如果您使用較新的.format方法,而不是%

def my_sprintf(format_str, li): 

    n = format_str.count('%') - 2*format_str.count('%%') 
    repeats = len(li)//n 

    return (format_str*repeats) % tuple(li[:repeats*n]) 

一個不太哈克的方式是可行的。在這種情況下,你可以使用string.Formatter().parse()方法來獲得在format_str使用的字段列表。然後

功能如下:

import string 

li = [1, 2, 3, 4, 5, 6, 7] 
format_str = '{:d} {:d} {:d}\n' 


def my_sprintf(format_str, li): 

    formatter = string.Formatter() 
    n = len(list(filter(lambda a: a[2] is not None, 
         formatter.parse(format_str)))) 

    repeats = len(li)//n 
    return (format_str*repeats).format(*li[:repeats*n]) 
1

如果你的用戶在塊大小傳給你可以使用grouper recipe的變化。

def sprintf(iterable,fmt, n): 
    args = zip(*[iter(iterable)] * n) 
    return "".join([fmt % t for t in args]) 

輸出:

In [144]: sprintf(li,"%.2f %.2f %d\n", 3) 
Out[144]: '1.00 2.00 3\n4.00 5.00 6\n' 

In [145]: sprintf(li,"%d %d %d\n", 3) 
Out[145]: '1 2 3\n4 5 6\n' 

您可以處理時,塊大小是不使用izip_longest和str.format列表大小的整數倍,但它不會讓你不示數指定類型:

from itertools import izip_longest 


def sprintf(iterable, fmt, n, fillvalue=""): 
    args = izip_longest(*[iter(iterable)] * n, fillvalue=fillvalue) 
    return "".join([fmt.format(*t) for t in args]) 

如果您拆分佔位符或讓用戶傳遞佔位符迭代,您可以捕獲所有潛在問題。

def sprintf(iterable, fmt, sep=" "): 
    obj = object() 
    args = izip_longest(*[iter(iterable)] * len(fmt), fillvalue=obj) 
    return "".join(["{sep}".join([f % i for f, i in zip(fmt, t) if i is not obj]).format(sep=sep) + "\n" 
        for t in args]) 

演示:

In [165]: sprintf(li, ["%.2f", "%d", "%.2f", "%2.f"]) 
Out[165]: '1.00 2 3.00 4\n5.00 6\n' 

In [166]: sprintf(li, ["%d", "%d", "%d"]) 
Out[166]: '1 2 3\n4 5 6\n' 

In [167]: sprintf(li, ["%f", "%f", "%.4f"]) 
Out[167]: '1.000000 2.000000 3.0000\n4.000000 5.000000 6.0000\n' 

In [168]: sprintf(li, ["%.2f", "%d", "%.2f", "%2.f"]) 
Out[168]: '1.00 2 3.00 4\n5.00 6\n'