190 likes | 205 Views
Learn how to perform operations on tuples and lists using pattern matching and explore examples of list comprehensions, zip function, and recursion.
E N D
List Operations CSCE 314 Spring 2016
Tuple and List Patterns • Pattern matching with wildcards for tuples • fst (a, _) = a • scd(_, b) = b • Pattern matching with wildcards for lists • pullsecond [_, a, _] = a • This implies a list of 3 elements • The _ indicates a single element of the list, when it is in the list. • The _ can also indicate an entire list • [ [a, b, c], _, _, [2, 4] ]
Building a list: the cons operator ‘:’ • <element> : <list> • cons adds one element to the front of a list > 1 : [2, 3, 4] [1, 2, 3, 4] • cons associates to the right: • [1, 2, 3] = 1 : (2 : (3 : [])) = 1: 2: 3: [] • Generally, should use parentheses to be clear! • cons makes it easier to match list patterns • (x:xs) – x is the first element in the list, xs is the remainder of the list
Examples • Patterns can be arbitrarily deep/complex. What are these patterns: f (a:b:c:d:e:fs) = a:b:c:d:e:[] • list of at least 5 elements • forms list of those first 5 g (_: (_, x): _) = x • list of tuples, each with two elements • takes second element of the second tuple h [[_]] = True • singleton list, each element is a singleton list • Identifies valid such lists, e.g. [[True]], or [[‘a’]], or [[1]]
List Comprehensions (list generators) • Can generate lists from other lists • [x+x | x <-[1..10] ] • [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] • Can use multiple generators • Applied left to right (like nested loops) • [(x,y) | x <- [1..3], y <- [11..13]] • [(1,11),(1,12),(1,13),(2,11),(2,12),(2,13),(3,11),(3,12),(3,13)] • Notice that all the (1,_) elements come before the (2,_) ones • Generators can use earlier generators (dependent generators) • [(x,y) | x<-[1..3], y<-[x..3]] • [(1,1),(1,2),(1,3),(2,2),(2,3),(3,3)]
Dependent generator example • What does this function do? somefuncxss = [x | xs <- xss, x <- xs] • First, the type: somefunc :: [[a]] -> [a] • Notice, we form xs from the elements of xss • Then, we form x from the elements of xs • And those x’s form the final list • These are the elements of the elements of the list • Basically, we concatenate the list somefunc [[1,2,3],[4],[5,6]] [1,2,3,4,5,6]
Guards • When using generators, we can apply guards, similar to the guards seen before • Given as expressions, separated by commas • Guards limit which combinations of generators are used (only the ones that give true guards [x | x <- [1..10], x<5] [1,2,3,4] [x | x <- [1..10], even x] [2,4,6,8,10]
List Comprehension example • Say we want a function that will list all primes up to n: • primes :: Int -> [Int] • First, we will create a function to compute all factors of a number: • A number x is a factor of a number y if y mod x == 0 factors :: Int -> [Int] factors n = [x | x <- [1..n], n `mod` x == 0] • Test: > factors 24 [1,2,3,4,6,8,12,24]
List comprehension example (continued) • Given factors, we want a function isprime • A number x is prime if its only factors are 1 and x isprime :: Int -> Bool isprime n = factors n == [1,n] • Test: > isprime 24 False > isprime 7 True
List comprehension example (continued • Given isprime, we can now write the primes function: primes :: Int -> [Int] primes n = [x | x <- [2..n], isprime x] • Test > primes 20 [2,3,5,7,11,13,17,19]
The zip function • A useful list operation. • Often as a tool in parts of bigger computation – to pair up items • Take two lists and form a list of tuples • Tuple is a pair, with one element from first list and corresponding from second • Length of list is the length of the shortest input list > zip [1,2,3,4,5,6,7],[“red”,”green”,”blue”,”cyan”,”magenta”,”yellow”] [(1,”red”),(2,”green”),(3,”blue”),(4,”cyan”),(5,”magenta”),(6,”yellow”)]
A zip example: testing for a sorted list • Want a check to see if a list is sorted sorted :: Ord a => [a] -> Bool • We first form pairs of adjacent elements in the list: pairs :: [a] -> [(a,a)] pairs xs = zip xs (tail xs) • Test: > pairs [1, 5, 8, 9] [(1,5),(5,8),(8,9)]
A zip example: testing for a sorted list (cont.) • Given pairs, the list is sorted only if all pairs are in order • Note: the and command, applied to a list, gives the “and” of all elements sorted :: Ord a => [a] -> Bool sorted xs = and [x<=y | (x,y) <- pairs xs] • Test > sorted [1,5,8,9] True > sorted [1,8,5,9] False
Recursion on lists • Recursion works just like it did with integers • Base case: typically the empty list [] • Use the cons operator (:) to break/construct lists • e.g. length [] = 0 length (_:xs) = 1 + length xs
Example: quicksort • Quicksort takes first element from a list, divides the remainder of the list into stuff before and stuff after, and then recursively sorts those. • First, create a list of elements greater than a given value biggerlist :: Ord a => a -> [a] -> [a] biggerlist n xs = [x | x <- xs, x > n] • Likewise, create a list of elements less than or equal to a given value smallerlist:: Ord a => a -> [a] -> [a] smallerlistn xs = [x | x <- xs, x <= n]
Example: quicksort (continued) • Now, quicksort is straightforward: quicksort :: [a] -> [a] quicksort[] = [] quicksort (x:xs) = quicksort (smallerlistx xs) ++ [x] ++ quicksort (biggerlistx xs)
Example: insert into ordered list insert :: Ord a => a -> [a] -> [a] insert x [] = [x] insert x (y:ys) | x <= y = x:y:ys | otherwise = y:insertx ys
Example: Insertion sort • Given the insert command, write insertion sort insort :: Ord a => [a] -> [a] insort [] = [] insort (x:xs) = insert x (insortxs)
Additional notes • Strings are just lists of characters • So, all the list commands can be applied to strings • Section 5.5 has an extended example of how to create, use, and crack the Caesar cipher • You should read this section, try it yourself, and make sure you understand how it works! • Ask questions if you have them, next class • We will next be looking more closely at recursion next time