根据函数的返回值创建表

时间:2012-06-25 00:36:00

标签: python

我有这个;

import operator
cuts = { "Emerald" : (10,125),
         "Oval" : (20,150),
         "Pear" : (35, 175),
         "Plumbbob" : (50,200),
         "Marquis" : (75, 230),
         "Crystal Ball" : (100, 260),
         "Brilliant" : (250, 350),
         "Star Cut" : (400,400),
         "Heart-shaped" : (1000, 500)
         }

def best(amount):
    "Returns most profitable cut's name."
    max_name = ""
    max_value = -10000
    for k,v in cuts.iteritems():
        value = ((float(amount) * (v[1] - 100) / 100)) - v[0]
        if value > max_value:
            max_value = value
            max_name = k
    return max_name

def create_table():
    """Creates a table like

       0-40 emerald
       40-45 Oval
       ...
       2000 + Heart-shaped
    """

但我仍然坚持写create_table。此代码用于帮助我正在玩的游戏。 best函数,给定金额,返回该金额最有利可图的剪切名称。我想创建一个显示范围的表格。例如,对于0-40之间的数量,最好的切割是祖母绿,40-45之间的最佳切割是椭圆形等。

2 个答案:

答案 0 :(得分:1)

def create_table():
    curname = None
    for amount in xrange(2500):
        name = best(amount)
        if name != curname:
            if curname is not None:
                print "%d-%d %s" % (minamt, amount-1, curname)
            curname = name
            minamt = amount
    print "%d-%d %s" % (minamt, amount-1, curname)

(未经测试,顺便说一句)

答案 1 :(得分:1)

分析解决方案无疑是矫枉过正......但是,嘿,我喜欢矫枉过正。

首先,我将cuts转换为y = mx + b格式:

cuts = [(k, (v1-100)*0.01,-v0) for k,(v0,v1) in cuts.items()]
cuts.sort()

导致

cuts = [
    ('Brilliant',       2.5,    -250),
    ('Crystal Ball',    1.6,    -100),
    ('Emerald',         0.25,    -10),
    ('Heart-shaped',    4.0,   -1000),
    ('Marquis',         1.3,     -75),
    ('Oval',            0.5,     -20),
    ('Pear',            0.75,    -35),
    ('Plumbbob',        1.0,     -50),
    ('Star Cut',        3.0,    -400)
]

对于每对切割,我可以找到交叉点 - 切割值相同的宝石大小

from itertools import combinations

xints = []
for (na,ma,ba),(nb,mb,bb) in combinations(cuts, 2):
    xint = (bb-ba)/(ma-mb)
    val = ma*xint + ba

    # figure out which cut dominates to the right
    va = ma*(xint+0.01)+ba
    vb = mb*(xint+0.01)+bb
    if vb > va:
        xints.append((xint,val,na,nb))
    else:
        xints.append((xint,val,nb,na))

这导致36个交叉点,其中大多数是多余的 - 其他一些切割在这一点上更有价值。所以我们过滤:

xints = [(xint,val,na,nb) for xint,val,na,nb in xints if all(nc==na or nc==nb or mc*xint+bc <= val for nc,mc,bc in cuts)]
xints.sort()

留下10个有效的交叉点:

[
    (40.0, 0.0, 'Emerald', 'Oval'),
    (60.0, 10.0, 'Oval', 'Pear'),
    (60.0, 10.0, 'Oval', 'Plumbbob'),
    (60.0, 10.0, 'Pear', 'Plumbbob'),
    (83.33333333333331, 33.333333333333314, 'Marquis', 'Crystal Ball'),
    (83.33333333333331, 33.333333333333314, 'Plumbbob', 'Crystal Ball'),
    (83.33333333333331, 33.333333333333314, 'Plumbbob', 'Marquis'),
    (166.66666666666669, 166.66666666666674, 'Crystal Ball', 'Brilliant'),
    (300.0, 500.0, 'Brilliant', 'Star Cut'),
    (600.0, 1400.0, 'Star Cut', 'Heart-shaped')
]

通过检查,我们发现梨和马奎斯的削减是多余的 - 它们仅在交叉点处具有竞争力 - 所以我们丢弃它们出现的4个项目,

[
    (40.0, 0.0, 'Emerald', 'Oval'),
    (60.0, 10.0, 'Oval', 'Plumbbob'),
    (83.33333333333331, 33.333333333333314, 'Plumbbob', 'Crystal Ball'),
    (166.66666666666669, 166.66666666666674, 'Crystal Ball', 'Brilliant'),
    (300.0, 500.0, 'Brilliant', 'Star Cut'),
    (600.0, 1400.0, 'Star Cut', 'Heart-shaped')
]

是最佳交叉点;然后你的桌子看起来像

Size      Value      Cut
----      -----     ------------
   0       -10
                    Emerald
  40         0
                    Oval
  60        10
                    Plumbbob
  83.33     33.33
                    Crystal Ball
 166.67    166.67
                    Brilliant
 300       500
                    Star Cut
 600      1400
                    Heart-shaped

严格来说,你可以放弃祖母绿切割,因为预期的值是负的(在任何小于40的宝石上切割会损失你的钱)。