2016-02-13 85 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'