在 Python、Ruby、Haskell 等中迭代列表

1 投票
5 回答
502 浏览
提问于 2025-04-16 13:51

更新:我意识到我提问的方式很糟糕。这是我重新整理后的版本。

考虑以下这个函数:

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)

如果你想查看这个回答的之前版本,可以看看编辑记录;因为内容变得有点长了。

撰写回答