如何将一个列表按照奇偶位置分成两个列表?

4

我想将任意列表按位置拆分成两个新列表,一个包含所有偶数元素,另一个包含所有奇数元素。

例如:

对于这样的列表:

["a", "b", "c", "d", "e"]

我该如何获得这样的两个列表:

(["a", "c", "e"], ["b", "d"])
3个回答

7

单次遍历和少量代码:

evensAndOdds : List a -> (List a, List a)
evensAndOdds =
  List.foldr (\item (a, b) -> (item :: b, a)) ([], [])

这里的技巧是在每次迭代时交换返回元组的元素位置,从而交替地将其中一个附加到另一个上,而无需跟踪索引。

聪明,但结果列表与原始顺序相反。 - MtnViewMark
1
@MtnViewMark 你真的检查过了吗?如果使用foldl,它会这样做,但是这里使用的是foldr - glennsl
2
当我检查时,它对我来说并没有看起来是反向的。 - ivarni

2

解决方案1:

evensAndOdds : List a -> (List a, List a)
evensAndOdds items
  let
    enum = List.indexedMap Tuple.pair items
    evens = List.filterMap (\(i, v) -> if modBy 2 i == 0 then Just v else Nothing) enum
    odds = List.filterMap (\(i, v) -> if modBy 2 i == 1 then Just v else Nothing) enum
  in
    (evens, odds)

解决方案2:
evensAndOdds : List a -> (List a, List a)
evensAndOdds =
  List.indexedMap (\i v -> (modBy 2 i == 0, v))
  >> List.partition Tuple.first
  >> Tuple.mapFirst (List.map Tuple.second)
  >> Tuple.mapSecond (List.map Tuple.second)

1
你也可以使用递归函数。对于初学者来说,它可能比fold更易读。
evensAndOdds : List a -> ( List a, List a )
evensAndOdds input =
    case input of
        [] ->
            ( [], [] )

        [ even ] ->
            ( [ even ], [] )

        [ even, odd ] :: tail ->
            let
                ( tailEvens, tailOdds ) =
                    evensAndOdds tail
            in
            ( even :: tailEvens, odd :: tailOdds )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接