正好19行的钻石Python

1 投票
5 回答
2495 浏览
提问于 2025-04-17 03:42

可能重复的问题:
ASCII Python Art # 2

i = 10
while i>0:
    print i*'*' + 2*(10-i)*' ' + i*'*'
    i -=1
for x in range(1,11):
    print x* '*' + 2*(10-x)*' '+ x*'*'
    x +=1

我想用星号(*)画一个19行的菱形。结果我得到了20行。
我想要的效果是:

********************
*********  *********
********    ********
*******      *******
******        ******
*****          *****
****            ****
***              ***
**                **
*                  *
**                **
***              ***
****            ****
*****          *****
******        ******
*******      *******
********    ********
*********  *********
********************

我该怎么才能去掉星号中间部分的高度重复呢?

谢谢!

5 个回答

2

我在找这个技巧的时候遇到了一些困难:

def diamond(ni):
    li = [ i*'*' + (2*(ni-i) - 1)*' ' + (i - i//ni)*'*'
           for i in xrange(ni,0,-1)]

    li.extend(i*'*' + (2*(ni-i) - 1)*' ' + (i - i//ni)*'*'
              for i in range(2,ni+1))

    return '\n'.join(li)


print diamond(7)

绘制

*************
****** ******
*****   *****
****     ****
***       ***
**         **
*           *
**         **
***       ***
****     ****
*****   *****
****** ******
*************

注意到

li.extend(i*'*' + (2*(ni-i) - 1)*' ' + (i - i//ni)*'*'
                  for i in range(2,ni+1))

做的事情和

    li = [ i*'*' + (2*(ni-i) - 1)*' ' + (i - i//ni)*'*'
           for i in xrange(ni,0,-1)]

是一样的(少了一行),不过顺序是反的,我们可以简化一下:

def symetric_diamond(ni):
    li = [i*'*' + (2*(ni-i) - 1)*' ' + (i - i//ni)*'*'
          for i in xrange(ni,0,-1)]
    li.extend(li[-2::-1])
    return '\n'.join(li)

请注意

print '\n'.join(str(i) for i in xrange(500))

会立刻显示,因为程序在打印之前先计算了字符串 '\n'.join(str(i) for i in xrange(500)),然后一次性打印出来,而

for i in xrange(500):
    print str(i)

显示起来要慢得多,因为计算机是一个接一个地打印500个字符串,每次调用 print 都比较耗时

还有另一种打印菱形的方法,我现在来写。

另外

def format_diamond(nl):
    ni = (nl+1)/2
    li = ['{:{fill}{align}{width}}'.format((2*(ni-x) - 1)*' ',fill='*',align='^',width=2*ni-1)
          for x in xrange(ni,0,-1)]
    li.extend(li[-2::-1])
    return '\n'.join(li)

-> 所有这些函数在 nl 为偶数时,都会生成 nl-1 行的菱形。

编辑

最后,我更喜欢的是:

def symetric_diamond(nl):
    '''Returns a diamond of nl lines if nl is odd, 
       and nl-1 lines if nl is even'''
    ni = (nl+1)//2
    li = [ (2*ni-1) * '*' ]
    li.extend(i*'*' + (2*(ni-i) - 1)*' ' +i*'*' for i in xrange(ni-1,0,-1))
    li += reversed(li[0:-1])  # in-place extension
    return '\n'.join(li)

因为使用了就地扩展(用 extend 和 reversed),而且没有那个可怕的 (i - i//ni)*'*'

2

你已经知道怎么打印每一行了。现在最后一步是生成正确的数字序列,以便让打印的行能够正确显示。

l = range(10,1,-1)
l.extend(range(1,11))
for x in l:
  print x*'*' + 2*(10-x)*' ' + x*'*'


[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
********************
*********  *********
********    ********
*******      *******
******        ******
*****          *****
****            ****
***              ***
**                **
*                  *
**                **
***              ***
****            ****
*****          *****
******        ******
*******      *******
********    ********
*********  *********
********************
2

基本的想法是决定哪个循环应该在每一行的两边只打印一个星号。然后修改另一个循环,使其不打印那一行(也就是说,不以两颗星的行开始或结束)。

for x in range(1,11):

改成

for x in range(2,11):

另外,你可以去掉最后一行,因为第二个循环已经自己处理了x的增加。

为了让代码更易读,我建议只使用一种类型的循环。

例如,你可以用这个方式写第一个循环(注意:这个循环不会运行x=1的情况,所以你需要使用未修改过的第二个循环版本)。

for x in range(10, 1, -1):
    print x* '*' + 2*(10-x)*' '+ x*'*'

撰写回答