Как разбить список на два списка по четным и нечетным позициям? - PullRequest
4 голосов
/ 24 сентября 2019

Я хочу разбить список элементов arbirtray по позициям на два новых списка, содержащих все четные и нечетные элементы.

Пример: с таким списком:

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

howМогу ли я получить два списка, как это:

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

Ответы [ 3 ]

7 голосов
/ 24 сентября 2019

Один проход и намного меньше кода:

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

Хитрость заключается в том, чтобы переключать положение элементов возвращаемого кортежа на каждой итерации, чередуя, таким образом, какой из них добавляется без необходимости отслеживатьиндекса.

2 голосов
/ 24 сентября 2019

Решение 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)
0 голосов
/ 26 сентября 2019

Вы также можете использовать рекурсивную функцию.Это может быть легче читать, чем 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 )
...