1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
|
-- #1 Find last element
myLast :: [a] -> a
myLast = last
mylast' = head . reverse
-- #2 Find second to last element
myButLast x = (reverse x) !! 1
-- #3 Find nth element
elementAt ls n = ls !! n-1
-- #4 Elements in a list
myLength [x] = 1
myLength (_:xs) = 1 + myLength xs
myLength' ls = helper ls 1 where
helper [_] accum = accum
helper (_:xs) accum = helper xs (accum+1)
-- #5 Reverse a list
myReverse [] = []
myReverse (x:xs) = myReverse xs ++ [x]
-- #6 Determine if list is a palindrome
isPalindrome ls = ls == reverse ls
-- #7 Flatten a nested list structure
-- New type, because haskell lists are homogenous
data NestedList a = Elem !a | List ![NestedList a]
nestedHead :: NestedList a -> a
nestedHead (Elem x) = x
nestedHead (List [x]) = nestedHead x
--nestedTail :: NestedList a -> NestedList a
--nestedTail (List x) = NestedList x
--flatten :: NestedList a -> [a]
--flatten xs = ne
-- Correct solution:
flatten :: NestedList a -> [a]
flatten (Elem x) = [x]
flatten (List x) = concatMap flatten x
-- #8 Eliminate consecutive duplicates
-- compress :: [a] -> [a]
-- compress a = helper a [] where
-- helper [] part = reverse part
-- helper [x] part = part
-- helper (x:xs) part@(p:ps)
-- | x == p = helper xs part
-- | otherwise = helper xs (x:part)
-- Correct solution:
compress [] = []
compress (x:xs) = x : compress (dropWhile (== x) xs)
-- #9 Pack consecutive duplicates into sublists
pack :: (Eq a) => [a] -> [[a]]
pack [] = []
pack (x:xs) = let (first,rest) = span (== x) xs
in (x:first) : pack rest
-- #10 Use previous to implement run-length encoding
encode :: (Eq a) => [a] -> [(Int, a)]
encode x = zip (map length group) (map head group)
where group = pack x
-- Simpler solution:
encode' xs = [(length x, head x) | x <- pack xs]
-- #11 Modify the previous result such that an element with no duplicates get copied
-- directly into the resulting list. Requires special type:
data ListItem a = Single !a | Multiple !Int !a
deriving (Show)
packToEnc :: Eq a => [a] -> ListItem a
packToEnc a@(fst:_)
| len == 1 = Single fst
| otherwise = Multiple len fst
where len = length a
encodeModified :: Eq a => [a] -> [ListItem a]
-- encodeModified xs = [Multiple (length x) (head x) | x <- pack xs]
encodeModified xs = map packToEnc (pack xs)
-- This can also be done with a list comprehension:
encodeModified' xs = [y | x@(fst:_) <- pack xs, let len = length x,
let y = if len == 1 then Single fst else Multiple len fst]
-- #12 Decode modified RLE list
-- decodeSingle :: ListItem a -> [a]
-- decodeSingle (Single x) = [x]
-- decodeSingle (Multiple n x) = replicate n x
decodeModified :: Eq a => [ListItem a] -> [a]
decodeModified = concatMap decodeSingle
where
decodeSingle (Single x) = [x]
decodeSingle (Multiple n x) = replicate n x
-- #13 Implement RLE directly (without packing first)
encodeDirect :: Eq a => [a] -> [ListItem a]
encodeDirect [] = []
encodeDirect (x:xs)
| len == 1 = Single x : encodeDirect rest
| otherwise = Multiple len x : encodeDirect rest
where (dups,rest) = span (== x) xs
len = length dups + 1
-- #14 Duplicate elements of a list
dupli :: [a] -> [a]
dupli [] = []
dupli (x:xs) = x : (x : dupli xs)
-- #15 Replicate the elements of a list a certain number of times
repli :: [a] -> Int -> [a]
repli [] _ = []
repli (x:xs) n = replicate n x ++ repli xs n
-- Better solution:
repli' xs n = concatMap (replicate n) xs
-- #16 Drop every nth element from a list
dropEvery :: [a] -> Int -> [a]
--dropEvery xs n = [ x | x <- zip xs $ cycle [1,2,3]]
-- Correct solution
dropEvery xs n = [ i | (i,c) <- zip xs (cycle [1..n]), c /= n]
-- #17 Split a list into two parts given the length of the first
split xs n = splitAt n xs
split' :: [a] -> Int -> ([a],[a])
split' (x:xs) n | n > 0 = let (f,l) = split' xs (n-1) in (x : f,l)
split' xs _ = ([], xs)
-- #18 Extract a slice from a list
slice :: [a] -> Int -> Int -> [a]
slice xs s f = [ i | (i, j) <- zip xs [1..], s <= j, j <= f]
-- A small improvement, since zip cuts off based on the shorter list:
slice' xs s f = [i | (i,j) <- zip xs [1..f], j >= s]
-- A completely different take:
slice'' xs i j = take (j-i+1) $ drop (i-1) xs
-- #19 Rotate a list n places to the left
rotate :: [a] -> Int -> [a]
rotate xs n
| n < 0 = drop l xs ++ take l xs
| otherwise = drop n xs ++ take n xs
where l = length xs + n
-- Simpler solution:
rotate' xs n = drop nn xs ++ take nn xs
where nn = n `mod` length xs
-- #20 Remove the kth element from a list
removeAt :: Int -> [a] -> (a, [a])
removeAt n xs = (xs!!(n-1), take (n-1) xs ++ drop n xs)
-- #21 Insert an element at the given position
insertAt :: a -> [a] -> Int -> [a]
insertAt x xs n = take (n-1) xs ++ x : drop (n-1) xs
-- #22 Create a list containing all integers in a given range
range :: Enum a => a -> a -> [a]
range i j = [i..j]
range' i j = i : range (i+1) j
-- #23 - #30 are all based on randomness
-- #31 Determine whether a given number is prime
isPrime n
| n == 2 = True
| otherwise = helper n 2 where
helper x y
| rem x y == 0 = False
| y*y > x = True
| otherwise = helper x (y+1)
-- #32 Determine the GCD of two numbers
euclid gcd 0 = gcd
euclid x y = euclid y (x `rem` y)
-- #33 Determine whether two numbers are coprime (relative primes)
coprime x y = euclid x y == 1
-- #34 Calculate Euler's totient function
totient n
| isPrime n = n-1
| otherwise = length $ filter (n `coprime`) [1..n-1]
isFactor n fac = 0 == rem n fac
-- #35 Find the prime factors of a positive integer
primeFactors n = filter isPrime $ filter (\f -> rem n f == 0) [2.. ceiling $ sqrt $ fromIntegral n]
-- Improved method which creates full factorization:
primeFactors' n = helper n 2 where
helper n f
| f*f > n = [n]
| rem n f == 0 = f : helper (div n f) f
| otherwise = helper n (f+1)
-- #36 Find prime factors with multiplicity
prime_factors_mult n = map swap $ encode' $ primeFactors' n
where swap (x,y) = (y,x)
-- #37 Improved totient
totient' n = foldr (\(p,m) a -> ((p-1) * (p ^(m-1))) * a) 1 (prime_factors_mult n)
-- #38 Compare totient and totient'
-- Time for totient 10090090: 1:16
-- Time for totient' 10090090: <1
-- #39 Find list of primes in a given range
primesR l u = filter (isPrime) [l..u]
-- #40 Find the Goldbach primes for a given number
-- goldbach n = foldr (\) n (primesR 2 n)
|