Как получить каждый Энный элемент бесконечного списка в Haskell?

Строго говоря, как я генерирую новый список каждого Энного элемента из существующего бесконечного списка?

Например, если список [5, 3, 0, 1, 8, 0, 3, 4, 0, 93, 211, 0 ...] затем получение каждого 3-го элемента привело бы к этому списку [0,0,0,0,0 ...]

33
задан Elmex80s 4 April 2019 в 13:06
поделиться

12 ответов

Моя версия, используя падение:

every n xs = case drop (n-1) xs of
              (y:ys) -> y : every n ys
              [] -> []

Редактировать: Это также работает для конечных списков. Для бесконечных списков только в списках раствор Чарльза Стюарта немного короче.

59
ответ дан 27 November 2019 в 17:21
поделиться

Мне не с чем это проверять на работе, но что-то вроде:

extractEvery m = map snd . filter (\(x,y) -> (mod x m) == 0) . zip [1..]

должно работать даже на бесконечных списках.

(Edit: test and corrected.)

.
16
ответ дан 27 November 2019 в 17:21
поделиться
[

]Используйте шаблон просмотра![

] [
{-# LANGUAGE ViewPatterns #-}

everynth n (drop (n-1) -> l)
  | null l = []
  | otherwise = head l : everynth n (tail l)
] [
] [

]Уродливая версия ответа Нефрубира сохранилась, поэтому комментарии имеют смысл.[

] [
everynth :: Int -> [a] -> [a]
everynth n l = case splitAt (n-1) l of
                 (_, (x:xs)) -> x : everynth n xs
                 _           -> []
]
2
ответ дан 27 November 2019 в 17:21
поделиться
[

]Компилятор или интерпретатор вычислит размер шага (вычитая 1, так как он основан на нулях):[

] [
f l n = [l !! i | i <- [n-1,n-1+n..]]
] [

][]Отчет Haskell 98: Arithmetic Sequences[][

]
11
ответ дан 27 November 2019 в 17:21
поделиться

Альтернативное решение для избавления от мода :

extractEvery n = map snd . filter ((== n) . fst) . zip (cycle [1..n])
10
ответ дан 27 November 2019 в 17:21
поделиться

Другой способ сделать это:

takeEveryM m lst = [n | (i,n) <- zip [1..] lst, i `mod` m == 0]

Еще один:

import Data.List

takeEveryMth m = 
  (unfoldr g)  . dr
     where 
       dr = drop (m-1)
       g (x:xs) = Just (x, dr xs)
       g []     = Nothing
4
ответ дан 27 November 2019 в 17:21
поделиться

Все решения, использующие zip и т. Д., Делают массу ненужных выделений. Как функциональный программист, вы хотите выработать привычку не выделять память, если в этом нет необходимости. Распределение дорого, и по сравнению с распределением все остальное бесплатно. И распределение не просто появляется в «горячих точках», которые можно найти с помощью профилировщика; если вы не обращаете внимания на распределение, оно убивает вас везде .

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

Вы могли подумать, что оптимизатор избавится от выделения памяти, но вы были правы только наполовину. GHC, лучшему в мире оптимизирующему компилятору для Haskell, удается избежать выделения пары на элемент; он объединяет композицию filter - zip в foldr2 . Размещение списка [1 ..] остается. Возможно, вы не думаете, что это так уж плохо, но слияние потоков, которое является современной технологией GHC, является несколько хрупкой оптимизацией. Даже экспертам сложно предсказать, когда это сработает, просто взглянув на код. Более общий момент заключается в том, что когда дело доходит до критического свойства, такого как распределение, вы не хотите полагаться на причудливый оптимизатор, результаты которого вы не можете предсказать . Пока вы можете писать свой код одинаково удобочитаемым способом, вам гораздо лучше никогда не вводить эти распределения.

По этой причине я считаю решение Нефрубира, использующее drop , безусловно, наиболее убедительным. Выделяются только те значения cons-ячеек (с : ), которые должны быть частью окончательного ответа. Кроме того, использование drop делает решение не просто простым для чтения: оно кристально чистое и, очевидно, правильное.

35
ответ дан 27 November 2019 в 17:21
поделиться

Начиная с первого элемента:

everyf n [] = []
everyf n as  = head as : everyf n (drop n as)

Начиная с n-го элемента:

every n = everyf n . drop (n-1)
13
ответ дан 27 November 2019 в 17:21
поделиться

Ответ Мхариса великолепен. Но мне нравится избегать использования \ , поэтому вот мой гольф:

extractEvery n
  = map snd . filter fst
  . zip (cycle (replicate (n-1) False ++ [True]))
11
ответ дан 27 November 2019 в 17:21
поделиться

Явная рекурсия - это зло! Используйте библиотеку, подобную как карта, фильтр, сгиба, сканирование, воспроизведение, и т. Д. Вс. Если это не делает код резко проще, чтобы прочитать даже для тех AU Fait с библиотеками, то он просто делает ваш код менее модульным, более многословным и сложным для рассуждения.

Серьезно, явные рекурсивные версии должны быть проголосовать до негативного для задания так же просто, как это. Теперь я думаю, что я должен сказать что-то конструктивное, чтобы сбалансировать мою остановку.

Я предпочитаю использовать карту:

каждый n xs = map (xs !!) [n - 1, n-1 + n ..]

, а не понимание списка JA, поэтому читатель не делает Т должен беспокоиться о том, что я есть. Но в любом случае это O (n ^ 2), когда это может быть o (n), так что, возможно, это лучше:

каждый n = карта (!! (N-1)). Итерация (падение n)

2
ответ дан 27 November 2019 в 17:21
поделиться

Я носил мою версию Haskell на днях, настолько непроверен, но следующее кажется немного более простым, чем другие (использующие сопоставление шаблонов и падение, чтобы избежать Zip и мода):

everynth :: Int -> [a] -> [a]
everynth n xs = y : everynth n ys
         where y : ys = drop (n-1) xs
10
ответ дан 27 November 2019 в 17:21
поделиться

extractEvery n l = la tête de carte (réitèrent (laissent tomber n) (la goutte (n-1) l))

j'allais sentir fier de moi-même, jusqu'à ce que j'aie vu que Greg est arrivé de la même réponse et avant moi

1
ответ дан 27 November 2019 в 17:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: