【问题标题】:How to compare in Python a number with every component of a list after modyfying it?修改后如何在Python中将数字与列表的每个组件进行比较?
【发布时间】:2020-08-28 10:41:21
【问题描述】:

因此,我在此代码中的主要目标是检查随机生成的数字 (s) 是否等于随机生成的数字列表中的任何其他组件。如果是这种情况,则应将已检查的号码添加到单个随机生成的号码中,标记为“已使用”,从列表中退出,然后重新开始该过程。如果有两个或多个数字不如单个随机生成的数字,都应“标记”并从列表中退出,但仅应将两个数字中最大的一个添加到单个生成的数字中下一个循环。最后它应该说明需要多少次循环才能将列表中的所有随机数“标记”并使用,或者循环通过而没有任何数字被“标记”

由于这个解释可能不清楚,我将在这里举一个例子。想象一下生成的单个数字 (s) 是 0.2,而随机生成的数字列表是 (0.2, 0.3, 0.4, 0.5)。该算法将首先检查 s 与 0.2,如果相等,s 将变为 0.2 + 0.2 = 0.4,0.2 将被“标记”并从池中退出,并且将开始一个新循环。在下一个循环中,算法将检查 0.3 和 0.4 是否等于或小于新的 s (0.4),因此两者都将被“标记”、停用,s 将变为 0.2 + 0.4 = 0.6。在最后一个循环中,0.5 将被标记并停用,s 将变为 0.2 + 0.5 = 0.7,需要 3 次循环来标记所有数字。

到目前为止,我已经想出了这个(请忽略有关随机数生成的规范)

import random
import numpy as np

for x in range(0, 101):
    s = random.gauss(0.5, 1)
    s = round(s, 2)
    if s < 0:
        s = 0
    if s > 1:
        s = 1
    print("This is S")
    print(s)
    ai = []
    ai_size = 10
    for i in range(ai_size):
        num = float(random.gauss(0.5,1))
        num = round(num, 2)
        if num < 0:
            num = 0  
        if num > 1:
            num = 1
        ai.append(num)

    print("This is the vector of Ai")
    print(ai)
    ai = sorted(ai)
    print("This is the vector numerically ordered")
    print(ai)
    ai_mean = (np.mean(ai))
    ai_var = (np.var(ai))
    print(ai_mean)
    print(ai_var)
    rev = 0
    loop = 0
    for i in ai:
            if s >= i:
                s +=  i
                rev += 1 
                loop += 1
                print("This is evolving S")
                print(s)
            else:
                 break
    print("Loop is over")        
    print("This is the number of elements within the list that are marked")
    print(rev)
    print("This is the number of loops")
    print(loop)
    ai_percentage = rev / ai_size * 100
    print("This is the percentage")
    print(ai_percentage)
    

这段代码的问题主要在于,当在任何给定循环中应该标记和退出多个数字时,它只会在进入下一个循环之前检查第一个数字,这意味着它总是以已标记的相同数量的循环和数字(而在很多情况下,循环的数量应该更小)。它还使 S 成为所有标记数字的连续总和(在前面的示例中,它将执行 0.2 + 0.2 + 0.3 + 0.4 + 0.5),而不是像我之前解释的那样保持原始 S 不变并仅添加最高标记数字在示例中。

任何与此相关的想法或提示将不胜感激。

【问题讨论】:

  • TLDR;你有什么问题?
  • 我的主要问题是我的代码不是将列表的所有数字与单个数字进行比较,而是仅在开始下一个之前满足比较要求的列表的第一个数字循环,人为地增加进行所有比较所需的循环次数
  • 对代码风格的注释:变量名应该以小写字母开头,大写开头是为Python中的类名保留的。
  • 我感觉如果这是一个更大系统的一部分,可能有更简单的方法来解决问题。是这样吗?或者这可能只是一个奇怪的特定编码挑战?

标签: python


【解决方案1】:

所以这个问题有两个部分:

让我们首先从概念上解决您提到的连续求和问题。由于我们不想连续求和,我们必须保留两个不同的部分,“base”和“delta”。我将使用base_s 作为基础,使用delta_s 作为增量:

import random
import numpy as np

for x in range(0, 101):
    base_s = random.gauss(0.5, 1)
    base_s = round(s, 2)
    if base_s < 0:
        base_s = 0
    if base_s > 1:
        base_s = 1
    delta_s = 0.0
    print("This is S")
    print(base_s + delta_s)

    # ...

    rev = 0
    loop = 0
    for i in ai:
        if base_s + delta_s >= i:
            delta_s = i
            rev += 1
            loop += 1
            print("This is evolving S")
            print(base_s + delta_s)
        else:
            break

    # ...

现在我们解决了小部分,让我们关注如何处理同时验证条件的多个元素。首先,python 有一个名为filter 的内置函数,它允许我们获取验证某些条件的序列的一部分。 filter 的第一个参数是一个函数,它将为每个元素调用,如果它返回 True,则将包含该元素,否则省略。 list(filter(lambda x: x &lt;= base_s + delta_s, ai)) 将返回 [0.2]list(...) 是将其转换回列表,因为它返回一种特殊类型的序列,lambda x: x &lt;= base_s + delta_s 只是定义一个函数的内联方式,该函数对小于或等于 s 的元素(基数加增量)返回 true .

现在让我们把它变成一个有用的功能。它将执行一个循环迭代,所以我们称之为iterate。第一个参数是数字列表,第二个参数是基数 S,第三个参数是 delta S(默认为 0.0)。我们还将循环和转速计数(默认为 1)作为第 4 和第 5 个参数。它将返回剩余的项目、最后的 s 以及循环和转速计数器。

def iterate(items, base_s, delta_s=0.0, loop=0, rev=0):
    # Compute s
    s = base_s + delta_s
    # Get the elements lower or equal to S
    extracted = list(filter(lambda x: x <= s, items))

    # If there are no elements, we don't have to iterate any longer
    if len(extracted) == 0:
        return items, s, loop, rev

    # Remove the lower or equal elements
    items = list(filter(lambda x: x > s, items))
    # Find the biggest  extracted element as this will be the new delta_s
    delta_s = max(extracted)
    # Update loop and rev counters
    loop += 1
    rev += len(extracted)

    # Once everything is updated we can call the same function again to do another loop
    return iterate(items, base_s, delta_s, loop, rev)

我们已经有了我们的函数,当调用一次时,它会根据需要进行尽可能多的迭代。这些函数称为递归函数,因为它们调用自己。第一个iterate调用会调用第二个,以此类推,然后当一个到达if len(extracted) == 0,这意味着不需要进行迭代,nexted调用将依次返回,给出最终结果。

它实际上可以做得更短(我把它留得更长,以便更容易理解):

def iterate(items, base_s, delta_s=0.0, loop=0, rev=0):
    s = base_s + delta_s
    extracted = list(filter(lambda x: x <= s, items))
    if len(extracted) == 0:
        return items, s, loop, rev
    return iterate(list(filter(lambda x: x > s, items)), base_s, max(extracted), loop + 1, rev + len(extracted))

要使用它来解决您的示例,您可以调用:

remaining_items, s, loop, rev = iterate([0.2, 0.3, 0.4, 0.5], 0.2)

我把它作为你的练习,把它引入你的代码,如果你发现它有任何问题,请发表评论,我会帮助你。

【讨论】:

  • 我运行了 3 次:第一次 s = 1,所以每个元素都在 1 个循环中被删除,并且 100% 被删除。第二个 s = 0.64ai = [..., 0.64, 1, 1, 1] 所以在第一次迭代中它删除了直到 0.64 并且在第二次迭代中它删除了剩余的,2 个循环,100% 删除。第三次s = 0ai = [0, 0, 0, 0.07, ...] 所以在第一次迭代中它删除了零并停在那里,1 个循环删除了 30%。
猜你喜欢
  • 2022-09-23
  • 2020-12-01
  • 2017-10-30
  • 2021-05-18
  • 1970-01-01
  • 1970-01-01
  • 2017-09-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多