【问题标题】:How would I find the distance between two elements in a list?如何找到列表中两个元素之间的距离?
【发布时间】:2019-03-26 02:13:59
【问题描述】:

我必须找到列表中两个元素首次出现之间的距离。我们使用的程序是 Haskell。我已经在线了几个小时,试图寻求有关如何开始或解决问题的方向的帮助。请帮忙!

这是我们定义它的方式: gap :: (Eq a) => a -> a -> [a] -> Maybe Int

这里有一些例子:

> gap 3 8 [1..10]
Just 5

> gap 8 3 [1..10]
Nothing

> gap 'h' 'l' "hello"
Just 2

> gap 'h' 'z' "hello"
Nothing

【问题讨论】:

标签: haskell


【解决方案1】:

预计运行速度很快的答案:

import Data.List (elemIndex)


gap :: Eq a => a -> a -> [a] -> Maybe Int
gap x y ls = elemIndex y $ dropWhile ((/=) x) ls             

如果您不想依赖Data.List,那么您必须编写并添加您自己的elemIndex'。

根据 Daniel Wagner 的反馈意见:

gap' :: Eq a => a -> a -> [a] -> Maybe Int
gap' x y ls
    | null ls'          = Nothing
    | head ls' == y     = Nothing 
    | otherwise         = elemIndex y ls'

    where

    ls' = dropWhile (\t -> t /= x && t /= y) ls

【讨论】:

  • 与我给 dfeuer 的评论相同:这似乎不符合规范。考虑例如gap 'a' 'b' "bacb" -- 这报告了Just 2,这显然是不正确的。 (Nothing、Just 1 或 Just (-1) 都可能是明智的选择,具体取决于您如何解释规范。)
  • 只有 2 对我来说似乎是正确的 @Daniel 。第二个示例表明第二个参数应该出现在列表中的第一个参数处或之后。在“bacb”上,gap 'a' 'a' 是 Just 0,gap 'a' 'c' 是 Just 1,gap 'a' 'b' is Just 2
  • @ATayler 第二个例子的返回值不是Just,所以我不明白在其他情况下如何使用它来支持返回Just。
  • @DanielWagner 我想我明白我们为什么会互相误解了。我的规范是,“找到第一个参数的第一次出现 o,然后只考虑第一次出现之后的列表的其余部分找到第二个参数的第一次出现,然后减去它们的索引,返回如果任何一个都找不到,那就什么都没有”。您的规范是“找到每个参数 o1 o2 的第一次出现并返回 if o1
  • @ATayler 我认为您对我对规范的解释的说法过于精确,因为我不知道在o1 <= o2 的情况下要返回什么(例如,似乎总是返回Just (o2-o1) 时o1 和 o2 都存在也与示例匹配)。但是,是的,我将“两个元素的第一次出现”解释为“每个参数的第一次出现”。也许像您建议的那样的一些额外条件是有意的,但没有说明额外的条件,示例输入-输出对并不意味着一个。
【解决方案2】:

我会这样做:

import Data.List (elemIndex)

gap :: Eq a => a -> a -> [a] -> Maybe Int
gap x1 x2 xs = do
    i <- elemIndex x1 xs
    j <- elemIndex x2 xs
    if i <= j
        then Just (j - i)
        else Nothing

感谢dfeuer 提醒我elemIndex 功能。

【讨论】:

  • 这是无缘无故的低效。 dropWhile 是正确的开始方式。
  • @dfeuer 我认为根据规范可以做到的效率差不多。如果我正确猜到了您对dropWhile 的想法,那么它将得到gap 'a' 'b' "bacb" 的错误答案。 (答案中的代码是否正确尚不清楚——规范有点模棱两可,我不得不说——但dropWhile 版本肯定会出错!)
  • @DanielWagner,这似乎有点模棱两可,但我明白你的意思。但是,这仍然不是最好的方法,因为它会遍历列表两次,保留内存。您可以使用稍微不同的 dropWhile 调用,或者避免多余的测试完成一些自定义的工作。
  • @dfeuer 我同意。如果没有优化,这段代码效率很低。但是,智能编译器很可能会执行循环融合以仅遍历列表一次。无论哪种方式,第一步是让程序正确,下一步是在必要时执行优化。如果这段代码效率低下并不重要,那就顺其自然吧。但是,如果您发现它只是一个性能瓶颈,那么您应该费心优化它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-28
  • 2019-07-10
  • 1970-01-01
  • 2013-10-09
相关资源
最近更新 更多