在 Elm 中,如何获得列表中的每个偶数索引和 return 作为另一个列表?

In Elm, how would you get every even index in a list and return as another list?

在 Elm 中,如何获取列表中的每个偶数索引并 return 作为另一个列表?

所以您只想 return 列表中的偶数索引项,对吗?

以下是编写自己的函数的方法。我们将编写一个辅助函数 everySecond_,它看起来像这样。

everySecond_ : List a -> Int -> List a
everySecond_ list index =
    case list of
        [] ->
            []

        hd :: tl ->
            if index % 2 == 0 then
                hd :: (everySecond_ tl (index + 1))
            else
                everySecond_ tl (index + 1)

此函数接受一个列表,以及一个表示该列表的当前头部具有的索引的数字。我们需要将其作为参数传递给函数。

然后我们进行模式匹配就行了。如果它是空的,我们 return 一个空列表;这标志着递归的结束。列表中的最后一个元素始终是一个空列表。如果它 不是 一个空列表,我们取头(第一个元素)和尾(代表所有内容的列表)。

如果我们的 index 参数是偶数(% 2 == 0 表示 "when divided by two, leaves no remainders"),我们想保留这个元素,所以我们将它附加到我们正在构建的列表的前面向上,并通过使用当前列表的尾部和递增的索引号再次调用 everySecond_ 继续构建。

如果不是偶数,我们不想保留这个元素,所以我们只是return everySecond_ tl (index + 1),链表的下一阶段,然后重复该过程。

这就是它的逻辑。但这意味着我们需要调用 everySecond_ [foo, bar, baz] 1 来使用我们的函数,始终传入 1 作为默认参数。这不直观。这就是为什么我们用下划线称它为 everySecond_ 的原因——这不是我们要让人们调用的,这是一个将存在于幕后的辅助函数。我们可以把它藏在后面

everySecond : List a -> List a
everySecond list =
    everySecond_ list 1

现在你调用 everySecond [foo, bar, baz] 并且它工作正常,基本上默认起始索引为 1。

一种更简单的方法是根本不跟踪索引,而是使用布尔值 (True/False)。你从一个 False 开始,而不是测试是否被 2 整除,你只是检查布尔值。如果为 True,则保留该元素,并使用 False 再次调用该函数;如果为 False,则忽略该元素并使用 True 再次调用该函数。

大多数时候,您不需要编写递归函数,因为您可以使用标准的辅助函数来为您完成。这是针对您的特定问题的解决方案:

takeEvenIndexes : List a -> List a
takeEvenIndexes l =
  l
  |> List.indexedMap (\ i x -> if i |> modBy 2 == 0 then Just x else Nothing)
  |> List.filterMap identity

indexedMap function is like a map but you can depend on the index of the value as well. And filterMap is like a map but you can discard some of the values by returning Nothing. Here it is applied to the identity函数,因为在上一行已经预先计算了过滤。