I have a database table that I have tried to model in OCaml. However, I get problems when I try to write a function that extracts columns. I have managed to write a function that takes a table with only one column, but if I have a table with more columns then I get a match failure. I would need help with how to denotate my table in my pattern matching.
(* Table with many columns *)
let tableWithManyColumns =
"carTable",
[ ("RegNumber", ["1";"2";"3";"4"]);
("Brand", ["BMW";"SAAB";"Volvo";"Jeep"]);
("Year",["2000";"2003";"2001";"2012"]);
];;
(*Table with one columns*)
let tableWithOneColumn = "carTable",
[
("RegNumber", ["1";"2";"3";"4"])
];;
(*Current extractColumn*)
let extractColumn (t:string * (string * string list) list) =
match t with
(a,[(b,c)])-> b;;
(* Returns Regnumber *)
extractColumn(tableWithOneColumn);;
(*Returns match failure*)
extractColumn(tableWithManyColumns);;
The pattern [(b,c)] matches with a singleton list of pairs. So it will match with [("hello", "world)] but will not match with [("hello", "world"); ("another", "pair")], or [] or any list which length is not equal to one. If you want to match with any list with length more than one, you need to use the first :: rest pattern, where first will match with the first element of the list, and rest with the rest part of the list (everything beyond the first element).
The following function will extract the name of the first column,
type column = string * string list (* name, values *)
type base = string * column list (* tableName, columns *)
let firstColumnName : base -> string = fun table -> match table with
| (_tableName, (columnName,_values) :: _otherColumns) -> columnName
| _ -> failwith "wrong table representation"
Example,
# firstColumnName tableWithOneColumn;;
- : string = "RegNumber"
# firstColumnName tableWithManyColumns;;
- : string = "RegNumber"
Related
I'm trying to make a function that will check how many characters are matching in a word
The characters are non-repeating A-Z. The position of the letters doesn't matter
INPUT target = "ABCDE" , attempt = "CDXYZ",
OUTPUT match = 2 letters (C & D)
I've managed to write a function that compares one character in a word, but I've no clue
how to make it compare every character.
import Data.List
--check if a char appears in a [char]
checkForCharInAWord :: [Char] -> Char -> Bool
checkForCharInAWord wrd lt = elem lt wrd
compareChars :: [Char] -> [Char] -> Int
compareChars = ?????
I would also like to know how to count the matching characters in case of words with repeating characters, the position of the letter doesn't matter. I.e:
INPUT target = "AAAB", attempt = "ABBB" OUTPUT match = 2 letters (A &
B)
INPUT target = "AAAB", attempt = "AABB" OUTPUT match = 3 letters (A,
A & B)
and finally how to count the matching characters in a word, but where position is also taken into consideration
INPUT target = "NICE", attempt = "NEAR" OUTPUT match = 1 letters (N)
-- correct letter and a correct position
INPUT target = "BBBB", attempt = "BABA" OUTPUT match = 2 letters (B,
B) -- correct letter and a correct position
In each case I need just a simple int output with a similarity rating between 0 and (max number of letters in a target word.
The method should be flexible enough to allow words of different length (however target and attempt word will always be of equal length).
Thanks!
Below function seems to work for point 3. It takes two formal parameters (w1 and w2) representing the two words you want to compare, creates a list of 2-tuples of the corresponding letters using the built-in zip function (where xs = zip w1 w2 ). Then it goes through this list of 2-tuples and for each tuple compares the two elements using a list comprehension with guard. If they match, it adds a 1 to the list, otherwise it does nothing. Finaly, it sums all elements of this list (sum [1 | x<-xs, fst x == snd x]).
match :: [Char] -> [Char] -> Int
match w1 w2 = sum [1 | x<-xs, fst x == snd x]
where xs = zip w1 w2
So im really confused as i am new to sml and I am having trouble with syntax of how i want to create my function.
the instructions are as follows...
numberPrefix: char list → string * char list
Write a function named numberPrefix that returns (as a pair) a string representing the digit characters at the
beginning of the input list and the remaining characters after this prefix. You may use the Char.isDigit and
String.implode functions in your implementation.
For example,
numberPrefix [#"a", #"2", #"c", #" ", #"a"];
val it = ("", [#"a", #"2", #"c", #" ", #"a") : string * char list
numberPrefix [#"2", #"3", #" ", #"a"];
val it = ("23", [#" ", #"a"]) : string * char list
Here is my code so far...
fun numberPrefix(c:char list):string*char list =
case c of
[] => []
|(first::rest) => if isDigit first
then first::numberPrefix(rest)
else
;
I guess what i am trying to do is append first to a seperate list if it is indeed a digit, once i reach a member of the char list then i would like to return that list using String.implode, but I am banging my head on the idea of passing in a helper function or even just using the "let" expression. How can I essentially create a seperate list while also keeping track of where i am in the original list so that I can return the result in the proper format ?
First of all, the function should produce a pair, not a list.
The base case should be ("", []), not [], and you can't pass the recursive result around "untouched".
(You can pretty much tell this from the types alone. Pay attention to types; they want to help you.)
If you bind the result of recursing in a let, you can access its parts separately and rearrange them.
A directly recursive take might look like this:
fun numberPrefix [] = ("", [])
| numberPrefix (cs as (x::xs)) =
if Char.isDigit x
then let val (number, rest) = numberPrefix xs
in
((str x) ^ number, rest)
end
else ("", cs);
However, splitting a list in two based on a predicate – let's call it "splitOn", with the type ('a -> bool) -> 'a list -> 'a list * 'a list – is a reasonably useful operation, and if you had that function you would only need something like this:
fun numberPrefix xs = let val (nums, notnums) = splitOn Char.isDigit xs
in
(String.implode nums, notnums)
end;
(Splitting left as an exercise. I suspect that you have already implemented this splitting function, or its close relatives "takeWhile" and "dropWhile".)
I am currently trying to do a spellcheck, but am having some trouble dealing with certain cases.
For example, given the string: { else"--but, }, my spellcheck automatically reads this as an invalid word. However, since else and but are both correctly spelled, I don't want to mark this as incorrect.
Is there any way I can do this with regular expressions?
A more common case I am having trouble with is things like "waistcoat-pocket".
Rather than a regular expression, you should use unicode word segmentation. With the uuseg and uucp library, you can extract words and filter word boundaries with
let is_alphaword =
let alphachar = function
| `Malformed _ -> false
| `Uchar x ->
match Uucp.Break.word x with
| `LE | `Extend -> true
| _ -> false
in
Uutf.String.fold_utf_8 (fun acc _ x -> acc && alphachar x) true
(* Note that we are supposing strings to be utf-8 encoded *)
let words s =
let cons l x = if is_alphaword x then x :: l else l in
List.rev (Uuseg_string.fold_utf_8 `Word cons [] s)
This function splits the string words-by-words:
words "else\"--but";;
- : string list = ["else"; "but"]
words "waistcoat-pocket";;
- : string list = ["waistcoat"; "pocket"]
and works correctly in more general context
words "आ तवेता नि षीदतेन्द्रमभि पर गायत";;
- : string list =
["आ"; "तवेता"; "नि"; "षीदतेन्द्रमभि";
"पर"; "गायत"]
or
words "Étoile(de Barnard)";;
- : string list = ["Étoile"; "de"; "Barnard"]
Say I have lists like [1;2;3;4;5;6;9] and [1;2;3;9] and I want to write a pattern which captures lists which begin with 1 and end with 9, and also capture the values of the middle of the list. Is this possible to do with OCaml's pattern matching?
I've tried to write something like
match l with
| 1::middle::9
or
match l with
| 1::middle::9::[]
but I'm not sure that these are doing what I want, and are probably instead only matching 3 element lists. Is there an approach I can take to match things like this? Should I be using nested pattern matches?
There's no pattern that matches the end of a list, so there's no pattern like what you want. You can do two matches:
match l with
| 1 :: _ -> (
match List.rev l with
| 9 :: _ -> true
| _ -> false
)
| _ -> false
Finding the end of a list is a linear time operation. If your lists can be long, you might want to use a different data structure.
If you're just making checks on the first and last elements of a list, you may want to use conditional statements instead of pattern matching:
let is_valid l =
let open List in
let hd' = hd l in (* Get the first element of the list *)
let tl' = rev l |> hd in (* Get the last element of the list *)
if hd' = 1 && tl' = 9 then true else false
is_valid [1;2;3;4;5;6;9] (* bool = true *)
However, if you are trying to extract that middle pattern it may be worthwhile to use pattern matching. We can do something similar to what Jeffery suggested because of the reason he pointed out (pattern matching can't match the end of a list):
let is_valid l =
let open List in
match l with
| 1 :: mid -> (* `mid` holds list without the `1` *)
(match rev mid with (* `rev_mid` holds list without the 9 but reversed *)
| 9 :: rev_mid -> Some (rev rev_mid) (* reverse to get correct order *)
| _ -> None)
| _ -> None
is_valid [1;2;3;4;5;6;9] (* int list option = Some [2; 3; 4; 5; 6] *)
Then with this function, you can use it with simple pattern matching to look for the middle of valid lists:
match is_valid l with
| Some middle -> middle (* the middle of the list *)
| None -> [] (* nothing — list was invalid *)
sorry if the questions to basic, but i havent been able to do this for some time. I have created a lists of lists in which the second array contains a parameter that can be either an f or a p. I need to create two new lists of arrays, one containing the items that have the f parameter and the other one containing the p parameter.
edit: trying to explain myself:
I have a list containing a series of facebook publications, and each one of this publications has information, such as what type of publication it is.. they can be either a p (text) or f (picture). What i need to do is to create two separate lists of this publications by the type publication they are.
example of data: [[|"publication0ID", "Poster0ID","TypeofPublication0"|];[|"publication1ID", "Poster1ID","TypeofPublication1"|]]
let data = [[|"publication0ID"; "Poster0ID"; "f"|];[|"publication1ID"; "Poster1ID"; "p"|]]
let texts, pictures =
data
|> List.partition (List.ofArray >> function
| _ :: _ :: "f" :: _ -> true
| _ :: _ :: "p" :: _ -> false
| _ -> failwith "neither f nor p"
)
This will split the lists according to the third "parameter", which you called "TypeOfPublication".
I changed your sample code, because your sub-arrays sub-lists contain only one tuple and judging by your "..." I tought that might be wrong.
To explain:
List.partition splits a list according to a function that is called for every element in the list. When the function returns true, the element will be put into the first list of the result tuple, and into the second list when false.
Since your elements are arrays also lists, it will be checked if the third element in the array list is either "f", which will cause the array list to be put in the texts result, and "p", which will be put into pictures.
If the third element is neither "f" nor "p", an exception will be thrown.
Update for the comment:
If your sub-arrays are always exactly three elements long, you can use this version:
let texts, pictures =
data
|> List.partition (function
| [| _; _; "f" |] -> true
| [| _; _; "p" |] -> false
| _ -> failwith "neither f nor p or wrong array length"
)
Or, you can use the first version and just put List.ofArray >> in between the function keyword and the opening paren so that it reads: List.partition (List.ofArray >> function (I updated the code above as well).
Assuming that your main list is of type (int, string) list list, then if you
let f = 1
let p = 1
you should be able to filter your main_list by using
let f_items = seq {
let! sub_list = main_list
let! (selector, item) = sub_list
if selector == f then
yield item
}
and likewise, to get the "p" items, you would use selector == p.
I had to bring out my F# book to be able to write this code, I haven't used F# for so long! I don't have F# on this computer, so I don't know if the above code actually works.