【问题标题】:DrRacket - Intermediate Student With Lambda - List orderingDrRacket - 使用 Lambda 的中级学生 - 列表排序
【发布时间】:2012-09-15 18:47:19
【问题描述】:

我有一个作业问题,要求我使用 lambda 编写一个函数,该函数使用一个数字列表并删除除每个数字第一次出现之外的所有数字。我的功能是我认为很好,除了它产生错误的结果!它生成一个列表,其中包含每个数字的最后一次出现。它生成一个与正确列表具有相同值的列表,只是顺序不同。这是我的代码:

    (define (remove-duplicates numlist)
      (foldr (lambda (a b) 
               (cond
                 [(not (member? a b)) (cons a b)]
                 [else b])) empty numlist))

我尝试过使用foldl 而不是foldr,但不出所料,它会生成正确的列表,但相反。有没有一种方法可以生成正确的列表,而无需使用另一个 lambda 表达式来反转 foldl 创建的列表?

请记住,这是作业,所以请不要明确回答。

谢谢大家!

【问题讨论】:

  • 例如,使用列表'(9 0 2 1 0 9 0 2 1 0) 应该产生'(9 0 2 1),而不是我得到'(9 2 1 0 )。谢谢。
  • 我有一个使用 foldl 的两种实现的解决方案,其中第一个使用第二个的结果作为递归列表。这似乎是需要额外迭代才能运行的伪劣代码......

标签: scheme racket fold


【解决方案1】:

从语义上考虑 foldr 的行为方式。它从列表的最右侧元素开始,并执行折叠,向左移动。这意味着在您的 lambda 函数中,a 表示直接位于迄今为止折叠列表左侧的元素,b 表示将所有内容折叠到列表元素 a 右侧的结果。考虑到这一点,请考虑:

[(not (member? a b)) (cons a b)]
[else b]

您检查列表b 是否已经包含a。如果是,那么您丢弃a,保持b 原样。这解释了为什么您的代码保留最后(最右边)出现,而不是第一次出现。如果你想正确弃牌,那么你必须改变你的逻辑。您需要以某种方式“清除”b 中包含的违规元素 a

[(not (member? a b)) (cons a b)]
[else (cons a (purge a b))]

这样,您最终将只保留每个唯一元素的最左侧,而不是最右侧。同时执行member?purge 可能是明智的,因为它们都必须遍历列表;这需要额外的重构。

请注意,由于该函数无论如何都需要 O(n2) 时间,因此添加 O(n ) 反转为foldl 版本。

【讨论】:

  • 我也会尝试使用本地定义进行清除,尽管我不允许显式实现递归 - 我会大便!谢谢丹。
  • Dan 可能更喜欢你给它一个 sh_o_t。 :)
猜你喜欢
  • 1970-01-01
  • 2020-03-12
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
  • 2019-03-25
  • 1970-01-01
  • 2014-04-12
相关资源
最近更新 更多