Saturday, 30 April 2016

Haskell: List Comprehensions


While studying basic mathematics, you may study set comprehensions.

For example, a set S = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} represent first 10 integers. We can write the above thing using set comprehension like 

We can write the same thing in Haskell like ‘[x | x <- [1..10]]’.
Prelude> [x | x <- [1..10]]  
[1,2,3,4,5,6,7,8,9,10]


Let’s add some conditions (predicates) to comprehensions. Predicates go after the binding parts and are separated from them by a comma.
Prelude> [x | x <- [1..10], x*2>=10]  
[5,6,7,8,9,10]
Prelude> [x | x <- [1..10], x*2>=10, x `mod` 3 == 0]  
[5,6,7,8,9,10]


Best way to learn list comprehensions is by practicing.

1. Get all the even numbers from a list
Prelude> let isEven n = (mod n 2) == 0
Prelude> let retainEven es = [n | n <- es, isEven n]
Prelude> 
Prelude> retainEven [1, 3, 2, 4, 5, 7, 6, 8, 10]
[2,4,6,8,10]


2. Get all even numbers which are greater than 6.
Prelude> let retainEvenGreaterSix es = [n | n<- es, isEven n, (n>6)]
Prelude> retainEvenGreaterSix [1, 3, 2, 4, 5, 7, 6, 8, 10]
[8,10]


3. Get all the first elements of list of tuples
Prelude> let firstElements tup = [(fst p) | p <- tup]
Prelude> 
Prelude> firstElements [(1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
[1,2,3,4,5]


4. Get all the second elements of list of tuples
Prelude> let secondElements tup = [(snd p) | p <- tup]
Prelude> 
Prelude> secondElements [(1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
[1,4,9,16,25]


5. Double all the first elements of list of tuples
Prelude> let doubleElements list = [2*x | (x, y) <- list]
Prelude> doubleElements [(1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
[2,4,6,8,10]


You can write above logic like below also.
Prelude> let doubleElements list = [2* (fst tup) | tup  <- list]
Prelude> doubleElements [(1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
[2,4,6,8,10]


6. Generate all pairs from two lists, such that first element from list 1 and second element form list 2.
Prelude> let getPairs list1 list2 = [(x, y) | x <- list1, y <- list2]
Prelude> 
Prelude> getPairs [1, 3, 5, 7] [2, 4, 6, 8, 10]
[(1,2),(1,4),(1,6),(1,8),(1,10),(3,2),(3,4),(3,6),(3,8),(3,10),(5,2),(5,4),(5,6),(5,8),(5,10),(7,2),(7,4),(7,6),(7,8),(7,10)]


7. Generate all pairs from two lists, such that first element from list 1 and second element form list 2 and sum of elements > 10.
Prelude> let getPairs list1 list2 = [(x, y) | x <- list1, y <- list2, (x + y) > 10]
Prelude> 
Prelude> getPairs [1, 3, 5, 7] [2, 4, 6, 8, 10]
[(1,10),(3,8),(3,10),(5,6),(5,8),(5,10),(7,4),(7,6),(7,8),(7,10)]


8. Double all odd numbers in a list
Prelude> let doubleOdds list = [2 * x | x <- list, odd x]
Prelude> 
Prelude> doubleOdds [1, 2, 3, 4, 5, 6, 7]
[2,6,10,14]


9. Get all the names from list, that start with character ‘S’.
Prelude> let getNames names = [name | name <- names, head name == 'S' ]
Prelude> 
Prelude> getNames ["Sailu", "Ptr", "Nayan", "Sailaja", "deva"]
["Sailu","Sailaja"]

10. Generate multiplication table of a number
Prelude> let mulTable num = [(num, x, num * x) | x <- [1..10]]
Prelude> mulTable 10
[(10,1,10),(10,2,20),(10,3,30),(10,4,40),(10,5,50),(10,6,60),(10,7,70),(10,8,80),(10,9,90),(10,10,100)]
Prelude> 
Prelude> mulTable 19
[(19,1,19),(19,2,38),(19,3,57),(19,4,76),(19,5,95),(19,6,114),(19,7,133),(19,8,152),(19,9,171),(19,10,190)]


11. Get the cross product of two lists.
Prelude> let crossProduct list1 list2 = [(x, y) | x <- list1,  y <- list2]
Prelude> 
Prelude> crossProduct [1, 2, 3] [4, 5, 6]
[(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]

12. Convert list of words to a sentence.
Prelude> let wordsToSentence list = [c | word <- list, c <- word]
Prelude> 
Prelude> wordsToSentence ["Hello", "PTR", "How", "are", "you"]
"HelloPTRHowareyou"


Observe above output, it is not looks like a sentence, let me add some space between words.
Prelude> let wordsToSentence list = [c | word <- list, c <- ' ' : word]
Prelude> 
Prelude> wordsToSentence ["Hello", "PTR", "How", "are", "you"]
" Hello PTR How are you"


13. Convert list of words to a sentence in upper case
Prelude> import Data.Char
Prelude Data.Char> let wordsToSentence list = [toUpper c | word <- list, c <- ' ' : word]
Prelude Data.Char> 
Prelude Data.Char> wordsToSentence ["Hello", "PTR", "How", "are", "you"]
" HELLO PTR HOW ARE YOU"


14. Square all the elements in a list
Prelude> let squareList list = [y | x <- list, let y =  x^2]
Prelude> 
Prelude> squareList []
[]
Prelude> 
Prelude> squareList [1, 2, 3, 4]
[1,4,9,16]


We can solve above problem in generic sense like below.

processData fun list = [y | x <- list, let y = fun x]
square x = x*x
cube x = x^3
Prelude> let processData fun list = [y | x <- list, let y = fun x]
Prelude> let square x = x*x
Prelude> let cube x = x^3
Prelude> 
Prelude> processData square [1, 2, 3]
[1,4,9]
Prelude> 
Prelude> processData cube [1, 2, 3]
[1,8,27]

15. Repeat every character in a string 5 times
Prelude> [ x|  x <- "hello", y<- [1..5]]
"hhhhheeeeellllllllllooooo"


16. Take list of numbers and return another list, where elements in the list are True, if the number in input list is even, else False.
Prelude> let isEvens list = [even x | x <- list]
Prelude> 
Prelude> isEvens []
[]
Prelude> isEvens [2, 4, 3, 5, 6]
[True,True,False,False,True]
Prelude> 
Prelude> isEvens [4, 5, 6, 7, 8]
[True,False,True,False,True]


17. Take a list of numbers as input and return list of even integers > 10.
Prelude> let getEvenGreat10 list = [x | x <- list, even x, x > 10]
Prelude> 
Prelude> getEvenGreat10 [2, 4, 6, 7, 9, 10, 14, 3, 2, 46]
[14,46]


18. Take list of tuples, where each tuple has two entries in it, calculate the sum of entries and return new list.
Prelude> let sumOfEntries list = [m+n | (m, n) <- list]
Prelude> 
Prelude> sumOfEntries [(2, 3), (4, 5), (6, 7), (8, 9)]
[5,9,13,17]


19. Check whether all the elements in a list are even (or) not
Prelude> let allEven list = (list == [x | x <- list, even x])
Prelude> 
Prelude> allEven [4, 5, 6]
False
Prelude> allEven [4, 8, 6]
True
Prelude> allEven []
True


20. Check whether all the elements in the lst are odd or not.
Prelude> let allOdd list = ([] == [x | x <- list, even x])
Prelude> 
Prelude> allOdd [4, 5, 6]
False
Prelude> 
Prelude> allOdd [3, 5, 7]
True


21. Convert every character in string to uppercase
Prelude> import Data.Char
Prelude Data.Char> 
Prelude Data.Char> let getUpper list = [toUpper x | x <- list ]
Prelude Data.Char> 
Prelude Data.Char> getUpper "Hello ptr, How are you"
"HELLO PTR, HOW ARE YOU"


22. Convert every character in string to uppercase and remove any digits in it.
Prelude> import Data.Char
Prelude Data.Char> 
Prelude Data.Char> let getUpper list = [toUpper x | x <- list, not (isDigit x) ]
Prelude Data.Char> 
Prelude Data.Char> getUpper "Hello ptr123, How are you123"
"HELLO PTR, HOW ARE YOU"


23. Get all divisors of a number.
Prelude> let divisors num = [x | x <- [1.. (num `div` 2)], num `rem` x == 0] ++ [num]
Prelude> divisors 20
[1,2,4,5,10,20]
Prelude> 
Prelude> divisors 100
[1,2,4,5,10,20,25,50,100]
Prelude> 
Prelude> divisors 181
[1,181]
Prelude> 
Prelude> divisors 81
[1,3,9,27,81]


24. Get all occurrences of a number in list.
Prelude> let getOccurrences num list = [x | x <- list, (x == num)]
Prelude> 
Prelude> getOccurrences 1 [1, 2, 3, 4, 1, 3, 1, 2]
[1,1,1]
Prelude> 
Prelude> getOccurrences 1 [1]
[1]
Prelude> 
Prelude> getOccurrences 1 [3, 5, 7]
[]
Prelude> 
Prelude> getOccurrences 1 [3, 5, 7, 1]
[1]


25. Implement quick sort
Sort.hs
qsort [] = []
qsort (pivot:xs) = qsort [x | x<-xs, x<pivot] ++ [pivot] ++ qsort [x | x<-xs, x>=pivot]

Prelude> :load Sort.hs
[1 of 1] Compiling Main             ( Sort.hs, interpreted )
Ok, modules loaded: Main.
*Main> 
*Main> qsort []
[]
*Main> qsort [1, 3, 5, 7, 2, 4, 6, 8]
[1,2,3,4,5,6,7,8]


We can add local bindings in List comprehensions.
Prelude> let processData fun list = [y | x <- list, let y = fun x]
Prelude> let sumSquare (x, y, z) = x^2 + y^2 + z^2
Prelude> 
Prelude> processData sumSquare [(1, 2, 3), (4, 5, 6)]
[14,77]


In my next post, I am going to explain a sample application, which is developed using list comprehensions.


Previous                                                 Next                                                 Home

No comments:

Post a Comment