在 Python、Ruby、Haskell 等中迭代列表
更新:我意识到我提问的方式很糟糕。这是我重新整理后的版本。
考虑以下这个函数:
myList = []
optimumList = []
def findOptimumListItems():
n = 5
for i in range (n + 1):
for j in range (n + 1 - i):
myList.append((i, j, n-i-j))
for i in myList:
win = 0.0
draw = 0.0
for j in myList:
score = 0
if (i[0] > j[0]):
score += 1
if (i[0] == j[0]):
score += 0.5
if (i[1] > j[1]):
score += 1
if (i[1] == j[1]):
score += 0.5
if (i[2] > j[2]):
score += 1
if (i[2] == j[2]):
score += 0.5
if (score == 2):
win += 1
if (score == 1.5):
draw += 1
if (win/(len(myList)-win-draw) > 1.0):
optimumList.append(i)
return optimumList
首先,我创建一个列表。比如当 n = 5 时,生成的列表是:
[(0, 0, 5), (0, 1, 4), (0, 2, 3), (0, 3, 2), (0, 4, 1),
(0, 5, 0), (1, 0, 4), (1, 1, 3), (1, 2, 2), (1, 3, 1),
(1, 4, 0), (2, 0, 3), (2, 1, 2), (2, 2, 1), (2, 3, 0),
(3, 0, 2), (3, 1, 1), (3, 2, 0), (4, 0, 1), (4, 1, 0),
(5, 0, 0)]
然后,这个函数会把列表中的每个元素和整个列表进行比较。具体怎么做呢?比如我在比较 [0, 0, 5] 和 [3, 1, 1]。0 比 3 小(所以得 0 分),0 也比 1 小,所以还是得 0 分,5 比 1 大(得 1 分)。平局得 0.5 分,赢得 1 分。对于任何一个元素,如果赢的次数比输的次数多,那么这个元素就被认为是最佳的,会被加入到最佳列表中。
当 n = 5 时,最佳列表是:
[(0, 2, 3), (0, 3, 2), (1, 1, 3), (1, 2, 2), (1, 3, 1), (2, 0, 3),
(2, 1, 2), (2, 2, 1), (2, 3, 0), (3, 0, 2), (3, 1, 1), (3, 2, 0)]
我的问题是:我该如何以一种简洁的方式来写这个函数?我特别想了解函数式算法。Python、Ruby、Java、Haskell 的答案都很受欢迎。(不过如果你有其他语言的好方案,也没问题。)
抱歉重复了同样的问题。我承认最初的问题很混乱,难以理解。希望现在清楚了。
更新(根据 rampion 的评论):有没有针对这个(或类似)问题的高效算法?
5 个回答
1
这还没有完成,但我觉得这是一个不错的开始。
这个是用Ruby语言写的。
>> l = [1,2,3]
>> l.map {|n| l.map{|i| i > n ? 1 : 0.5 }}.flatten.inject(0){|start, n| start + n}
=> 6.0
4
在Haskell语言中:
optimize :: Int -> [(Int,Int,Int)]
optimize n = filter optimal [ (a,b,c) | a <- [0..n], b <- [0..(n-a)], let c = n - a - b ]
where optimal x = (>0) . sum $ map (comp x) xs
comp (a,b,c) (a',b',c') = signum $ vs a a' + vs b b' + vs c c'
vs x x' = case compare x x' of
GT -> 1
EQ -> 0
LT -> -1
虽然这个写法很简洁,但效率不高(我们把(0,3,2)和(0,2,3)进行比较,反过来也一样,其实只需要比较一次就够了)。
4
第二次更新: 太好了——现在我完全明白你想要的是什么了。这段代码和你最近修改的代码做的事情是一样的:
def optimize(myList):
score_tup = lambda tup_a, tup_b: sum(1.0 if a > b else 0.5 if a == b else 0 for a, b in zip(tup_a, tup_b))
scores = ((tup_a, [score_tup(tup_a, tup_b) for tup_b in myList]) for tup_a in myList)
scores = ((tup, score.count(2), score.count(1.5)) for tup, score in scores)
return [tup for tup, win, draw in scores if (win * 1.0 / (len(myList) - win - draw)) > 1.0]
a = 5
myList = [(i, j, a-i-j) for i in range(a + 1) for j in range(a + 1 - i)]
print myList
print optimize(myList)
如果你想查看这个回答的之前版本,可以看看编辑记录;因为内容变得有点长了。