Thursday, June 11, 2009

APIIT haskell Assignment

type Table = ( String, [String], [[String]])
top10:: Table
top10 = ("LargestCountries",[ "Rank","Country", "Area"],[ [ "1", "Russia", "17075400"] , [ "2", "Canada", "9976140"] , [ "3", "United States", "9629091"] , [ "4", "China", "9596960"] , [ "5", "Brazil", "8511965"] , [ "6", "Australia", "7686850"] , [ "7", "India", "3287590"] , [ "8", "Argentina", "2776890"] , [ "9", "Kazakhstan", "2717306"] , [ "10", "Sudan", "2505810"]] )

-- DYNAMIC FORMATING

formatSingleRow :: [String] -> [Int] -> String -- formats a single row
formatSingleRow [][] = "|"
formatSingleRow (x:xs) (y:ys) = "| " ++ addSpace y x ++ formatSingleRow xs ys
where addSpace a b | length b > a = b | otherwise = addSpace (a-1) b ++ " " --adds white space based on the length of the string in the data feild

formatValues :: [[String]] -> [Int] -> String --formats records via formatsingrow function
formatValues [] _ = "\n"
formatValues ((x:xs)) (y:ys) = formatSingleRow x (y:ys) ++ "\n" ++ formatValues xs (y:ys)

writeTable :: Table -> String -- converts the table to a string
writeTable (x,y,z) = x ++ "\n\n" ++ formatHeader y ([ a+10|(a)<-(map length y)]) ++ formatValues z ([ a+10|(a)<-(map length y)]) --format column names and calls the formatValues function to format data
where formatHeader x y = formatSingleRow x y ++ "\n" ++ addLine ((length y)*18) "-" ++ "\n" -- header is formated using formatSingleRows function then a line is added underneath it
where addLine a b | length b == a = b |otherwise = b ++ addLine (a - 1) b -- calulates the length on this line. this can be different depending on how many columns are printed
-- END FORMATING

printTable::Table->IO() -- prints table
printTable = putStr.writeTable

--SELECTION OF COLUMNS

--filters a list of lists (i.e the data portion of the Table to output a single column based on index of the list
--using primitve recursions over lists.
--this function using the zip function to make tupes to identify the index of the list

filterByIndex::[[String]]->Int->[[String]]
filterByIndex [] _ = []
filterByIndex (x:xs) y = [[value]|(value,ind)<-(zip x [0..]),ind==y] ++ filterByIndex xs y

--adds a lists of lists to another list of lists , i.e adds to columns such as "Rank" and "Country"
--the tradition "++" function will not add it correctly it will just append one list to another
--this function mimics the Zip functions fuctionality but it stead of tupes it returns a list of lists
--with in the list comprehension, an attemp was made first to use "++", wh but it causes winHugs to crash after a few
--adds white space based on the length of the string in the data feild runs, so current method was implemented.
--the cause of this error is not know, possibly a bug in the compliler.

addListofLists::[[String]]->[[String]]->[[String]]
addListofLists x [] = x
addListofLists (x:xs) (y:ys) = [[ a |a<-x] ++ [ b |b<-y ]] ++ addListofLists xs ys

-- filters list based on given field names eg ["Rank","Country"], given table name
-- this function can take any number of feilds to filter, it can have dulplicate feilds too.
-- it then filters the data with a help "idx"
-- the purpose of "idx" is to get the index of the columns that need to be filtered
-- this index values will match those of the data fields. which then are selected
-- "idx" using zip function from the prelude library to create tuples for the indexing process
-- multiple columns are achieved with the help of primitive recursion over lists
-- feild names should match that of the table, eg:- if "Rank" was renamed to "id" in table schema
-- then that change should be reflected when calling the function, ["id","Country"]

projectDataColumns :: [String] -> Table -> [[String]]
projectDataColumns [] _ = []
projectDataColumns (x:xs) (a,b,c) = addListofLists (filterByIndex c (idx x b)) (projectDataColumns xs (a,b,c))
where idx x y = [ind|(value,ind)<-(zip y [0..]),value==x]!!0


-- this is the function that acutally prints outs the columns,
-- function definition would match that of the assignment question
-- it takes in feild names and table name as parameters
-- pattern matching is used to split the table in to a,b,c
-- of which "b" is replaced by the feilds requested byt he user, which is input X
-- "c" is the data portion which is filtered based on X using the previously defined functions
-- to test this function use any of the following lines of code
-- printTable.project["Rank", "Country"]$top10
-- printTable.project["Rank", "Country", "Area"]$top10
-- printTable.project["Rank", "Area", "Country", "Area"]$top10

project::[String]->Table->Table
project x (a,b,c) = (a, x,(projectDataColumns x (a,b,c)))

--SELECTION OF ROWS

-- this function filters the data rows based on a user defined predicate
-- (String->Bool) , it uses the "idx" function that was used in the
-- project data columns function
-- it uses the lambda notation to filter rows based on the user given
-- predicate, it can take in any feild name to fitler the data
-- eg, "Rank", "Country", "Area"
-- this fucntion uses a combination of prelude funtions such as zip, filter,!!
-- and pattern matching to accomplish its goal.
-- to test the function the folling code can be tried on winHugs
-- printTable.select "Rank" p $ top10 where p x = read x < (6::Int)
-- filters less than 6 on rank field
-- printTable.select "Rank" p $ top10
-- where p x = ( read x < (6::Int) && read x > (2::Int) )
-- filters countires with rank between 2 and 6, not inclusive
-- printTable.select "Rank" p $ top10 where p x = read x == (7::Int)
-- gets country with rank 7
-- printTable.select "Country" p $ top10 where p x = x == "Australia"
-- gets row for Australia
-- printTable.select "Area" p $ top10 where p x = read x < (10000000::Int)
-- gets countries with Area less than 10000000


select::String->(String->Bool)->Table->Table
select feild condition (a,b,c) = (a,b,((filter (\x -> condition (x!!(idx feild b))))c))
where idx x y = [ind|(value,ind)<-(zip y [0..]),value==x]!!0


1 comment:

  1. Hi, thanks for grate post, I copy ur code and I have error ! file:.\a.hs:10 - Syntax error in input (unexpected keyword "where") , if possible for u please upload the file or send me the file as mail plssssssssssssss.mh2001j@hotmail.com

    ReplyDelete