2011-09-29 6 views
5

Duplicar posible:
How to get every Nth element of an infinite list in Haskell?Cómo seleccionar todos los elementos de orden n de una lista

tarea simple - tenemos una lista y queremos dejar sólo cada elemento número n de esa lista . ¿Cuál es la forma más idiomática de hacerlo en Haskell?

la parte superior de la cabeza que es algo así como:

dr n [] = [] 
dr n (x : xs) = x : (dr n $ drop n xs) 

pero tengo una fuerte sensación de que estoy complicar el problema.

+2

que se ve bastante idiomática para mí. –

+2

no creo que vayas a obtener este más barato - se ve bien para mí. El único punto es que esto no encaja bien con su descripción ya que 'dr k [1 ..]' no produce la secuencia de preguntas. – Carsten

Respuesta

10

Su solución está bien, pero aquí hay otras tres soluciones que utilizan funciones de la biblioteca base de Haskell.

dr1 m = concatMap (take 1) . iterate (drop m) 

De grueso, esto nunca va a terminar (porque nunca se termina iterate). Así que tal vez una mejor solución sería utilizar unfoldr:

{-# LANGUAGE TupleSections #-} 
import Data.Maybe 
dr2 m = unfoldr ((\x-> fmap (,drop m x) (listToMaybe x))) 

La función se pasa a un Despliegue puede ser un poco desagradable si no sabe extensiones de GHC y conceptos tales como funtores, aquí es que la solución de nuevo sin el fantasía pies de trabajo (no probado):

dr2 m = unfoldr ((\x -> case listToMaybe x of 
         Nothing -> Nothing 
         Just i -> Just (i,drop m x))) 

Si no les gusta despliega entonces considerar una cremallera y un filtro:

dr3 m = map snd . filter ((== 1) . fst) . zip (cycle [1..m]) 

Revisión

Comprender todas estas soluciones es ligeramente diferente. Aprender por qué te hará un mejor programador de Haskell. dr1 utiliza Iterar y por lo tanto nunca se terminan (tal vez esto está bien para listas infinitas, pero probablemente no es una buena solución global):

> dr1 99 [1..400] 
[1,100,199,298,397^CInterrupted. 

La solución dr2 mostrará todos los valores m º omitiendo los valores en el Despliegue. El despliegue pasa tanto el valor que se utilizará para el siguiente despliegue como el resultado del desplegado actual en una sola tupla.

> dr2 99 [1..400] 
[1,100,199,298,397] 

La solución dr3 es un poco más largo, pero probablemente más fácil para un principiante de entender. Primero etiqueta cada elemento en la lista con un ciclo de [1..n, 1..n, 1..n ...]. En segundo lugar, selecciona solo los números etiquetados con 1, salteando efectivamente n-1 de los elementos. En tercer lugar, eliminas las etiquetas.

> dr3 99 [1..400] 
[1,100,199,298,397] 
+0

Thomas, muchas gracias. Es muy importante conocer todas las formas en que puede realizar tareas relativamente simples, y me acaba de dar algunas ideas nuevas. – shabunc

13

Mi variante sería:

each :: Int -> [a] -> [a] 
each n = map head . takeWhile (not . null) . iterate (drop n) 

rápida y juega bien con pereza.

+0

este es bueno! – shabunc

+1

sí, es muy agradable. No quería entrar en discusiones sobre la pereza (y sinceramente no consideré agregar una guardia nula) pero esta es una buena alternativa a mi primer ejemplo roto. –

8

¡Muchas maneras de afeitar este yak!Aquí tenemos otro:

import Data.List.Split -- from the "split" package on Hackage 
dr n = map head . chunk n 
+0

fragmento se implementa muy parecido, en realidad '- | dividida a intervalos regulares trozo :: Int -> [a] -> [[a]] trozo _ [] = [[]] trozo n xs = y1: trozo n y2 donde (y1, y2) = splitAt n xs' – shabunc

+0

@shabunc ¡Usted apuesta! La reutilización del código es el nombre del juego. –

0

Prueba esto:

getEach :: Int -> [a] -> [a] 
getEach _ [] = [] 
getEach n list 
| n < 1  = [] 
| otherwise = foldr (\i acc -> list !! (i - 1):acc) [] [n, (2 * n)..(length list)] 

Luego, en GHC:

*Main> getEach 2 [1..10] 
[10,8,6,4,2] 
+1

Esta solución no funciona para listas infinitas (debido a 'length list'); pierde espacio (fuerza el lomo de la lista, pero no libera el comienzo de la lista hasta que finaliza); es ineficiente en la búsqueda de elementos de la lista ('!!' es O (n); este es un [algoritmo de Schlemiel el Pintor] (http://en.wikipedia.org/wiki/Schlemiel_the_Painter%27s_algorithm)); y es demasiado complejo – dave4420

Cuestiones relacionadas