I am trying to use List.sort on a char list list list where the inner most list is representative of a word and I can use the compare compare function to sort the inner most by alphabetical order. I'm wondering what the compare function looks like? It has type 'a -> 'a -> int.
OK, so char list is a word, and char list list is word list. You are sorting a list of word lists. What is alphabetical order for word lists? Which comes first, "biker" or "bike shorts"? Dictionaries don't agree on the order.
If you want "bike shorts" to come first, this is (recursive) lexicographic order.
It so happens that the built-in polymorphic compare uses lexicographic order. So you could just use it straight out of the box:
# List.sort compare [[['b'; 'i'; 'k'; 'e'; 'r']];
[['b'; 'i'; 'k'; 'e']; ['s'; 'h'; 'o'; 'r'; 't'; 's']]];;
- : char list list list =
[[['b'; 'i'; 'k'; 'e']; ['s'; 'h'; 'o'; 'r'; 't'; 's']];
[['b'; 'i'; 'k'; 'e'; 'r']]
If you want to write your own compare function it's just a function with two parameters of the type you want to sort. To sort lists of words in an order that ignores spaces between words you could use this compare function:
let catcompare a b = compare (List.concat a) (List.concat b)
# List.sort catcompare [[['b'; 'i'; 'k'; 'e']; ['s'; 'h'; 'o'; 'r'; 't'; 's']];
[['b'; 'i'; 'k'; 'e'; 'r']]];;
- : char list list list =
[[['b'; 'i'; 'k'; 'e'; 'r']];
[['b'; 'i'; 'k'; 'e']; ['s'; 'h'; 'o'; 'r'; 't'; 's']]]
If what you're saying is that you want to sort the inner lists, then the question isn't about the comparison function. You can use the same built-in compare. The real question is how to apply a function to all the elements of a list and collect up the results into a list. (I'll leave this as an exercise. If you're already using List.sort you should know where to look for possible ideas.)
Related
operator (-): string → string → string that subtracts the letters in a string from the letters in another string, e.g., "Walcw Cacdsa"-"abcwxyz" will give "Wlw Cds" note that the operator - is case sensitive
I try with this code but don't work and tell me Syntax error.
let sub str =
for i = 0 to String.length str - 1 do
let string = Char.escaped str.[i] in
if string = "c" then str.replace(string, " ")
else let s3 = s3^string
done;;
Strings are an interesting thing to work with in OCaml. They're immutable meaning we have to create a new string rather than modifying the one passed in, but not readily pattern-matched. There are regular expressions, which make this kind of problem trivial, but it would be a lot easier if we had a list or sequence of characters, instead of a string.
Imagine if we had a list of integers and wanted to remove the integers in a second list from it using sequences.
let remove_ints lst lst_to_remove =
lst
|> List.to_seq
|> Seq.filter
(fun x ->
lst_to_remove
|> List.to_seq
|> Seq.exists ((=) x)
|> not)
|> List.of_seq
Here the list is converted to a sequence, then filtered based on that int not appearing in a sequence created from the list of ints to remove. Finally, that filtered sequence is converted back into a list.
If I want to make this an operator (using - is a bad idea in practice but we'll use it for now), you can easily do that.
let (-) = remove_ints
utop # [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] - [5; 6; 2];;
- : int list = [1; 3; 4; 7; 8; 9; 10]
This same logic can be applied to removing all of the characters in a string from another string. You simply need to convert a string to and from a sequence.
I have an example:
val lst1 : char list list =
[['l'; 'a'; 'n'; 'e']; ['p'; 'l'; 'a'; 'n'; 'e'; 't']; ['m'; 'o'; 'o'; 't'];
[]; []; ['s'; 'm'; 'o'; 'o'; 't'; 'h']; ['h'; 'a'; 'n'; 'g']; [];
[]; ['c'; 'h'; 'a'; 'n'; 'g'; 'e']; ['w'; 'e'; 'n'; 't']; []; []; etc.]
What is a trick to convert this list into something like:
["lane";"planet";...]?
Thank you.
Here is a very compact implementation:
let to_str_list =
List.map (fun cs -> String.concat "" (List.map (String.make 1) cs))
It looks like this when your call it:
# to_str_list [['h';'e';'l';'l';'o'];['w';'o';'r';'l';'d']];;
- : string list = ["hello"; "world"]
Update
If you want to suppress empty strings at the outer level you can do something like this:
let to_str_list css =
List.map (fun cs -> String.concat "" (List.map (String.make 1) cs)) css |>
List.filter ((<>) "")
It looks like this when you call it:
# to_str_list [['h';'e';'l';'l';'o']; []; ['w';'o';'r';'l';'d']];;
- : string list = ["hello"; "world"]
This should do it,
let to_string l =
let rec loop buf = function
| [] -> Buffer.contents buf
| x :: tl -> Buffer.add_char buf x; loop buf tl
in
loop (Buffer.create 100) l
let to_str_lst l = List.map to_string l
Alternate version of to_string without rec -
let to_string l =
List.fold_left
(fun acc e -> Buffer.add_char acc e; acc)
(Buffer.create 100)
l
|> Buffer.contents
Sample usage in utop:
to_str_lst [['h';'e';'l';'l';'o']; ['w';'o';'r';'l';'d']];;
returns
- : string list = ["hello"; "world"]
i whant generate a random permutation of elements of a list,
Example:
listString = ["a"; "b"; "c"; "d"; "e"; "f"]
i whant something like:
result = ["a"; "e"; "f"; "b"; "d"; "c"]
but that result change in each call of the function.
So when i call the function in second time return something like:
result = ["c"; "d"; "b"; "f"; "e"; "a"]
i found the solution:
let shuffle d = begin
Random.self_init ();
let nd = List.map (fun c -> (Random.bits (), c)) d in
let sond = List.sort compare nd in
List.map snd sond
end
the line Random.self_init (); Initialize the generator with a random seed chosen in a system-dependent way.
I'm learning f# with no prior functional programming background - starting to make progress but been stuck on this one. Could anybody please help me understand the solution to Problem 9 of the 99 f# problems - they can be found here:[http://fssnip.net/an][1]
Basically I don't understand how the pattern matching works in the provided solution. For a start what is xss? cheers for any help!
Problem 9 : Pack consecutive duplicates of list elements into sublists.
If a list contains repeated elements they should be placed in separate sublists.
Example:
pack ['a'; 'a'; 'a'; 'a'; 'b'; 'c'; 'c'; 'a'; 'a'; 'd'; 'e'; 'e'; 'e'; 'e']
val it : char list list =
[['a'; 'a'; 'a'; 'a']; ['b']; ['c'; 'c']; ['a'; 'a']; ['d']; ['e'; 'e'; 'e'; 'e']]
Sample Solution;
let pack xs =
let collect x = function
| (y::xs)::xss when x = y -> (x::y::xs)::xss
| xss -> [x]::xss
List.foldBack collect xs []
To understand this, it is first important to understand how lists are represented in F#. An F# list is either:
an empty list written as [] or
a value (head) followed by another list (tail) written as head::tail
So if you write, for example, [ 1; 2; 3 ] you are actually constructing a list containing 1, followed by a list containing 2, (etc.) followed by an empty list. The expression is compiled to:
1::(2::(3::[]))
And you can omit the brackets and write just 1::2::3::[].
Pattern matching uses exactly the same syntax, but in the opposite direction. Instead of constructing lists, you are decomposing them. So when you have a pattern x::xs it means that you want to take the first element and assign it to a variable x and the remaining list should be assinged to a variable xs.
The pattern (x::xs)::xss is a bit more tricky, because it works on lists of lists. This means that the head of the list you match on is also a list. You could rewrite the code to the following simpler version:
let pack xs =
let collect x = function
| head::xss -> // Decompose into first element (head) and the rest (tail)
match head with
| y::xs when x = y -> (x::y::xs)::xss
| _ -> [x]::xss
| xss -> [x]::xss
List.foldBack collect xs []
Now you have some duplication in the code, but you can see that collect takes x and another parameter, matches that another parameter against head::xss (to get the head/tail) and then also decomposes the head.
(y::xs)::xss matches a (non-empty) list of lists, y and xs being the head and tail of the first sublist and xss being the tail of the outer list. xss, in the second case, matches the entire list (empty or not).
foldBack (('T -> 'State -> 'State) -> 'T list -> 'State -> 'State) threads an accumulator argument through the list, going from back to front.
collect is the "accumulating" function, which basically reads: if the state (initially an empty list) contains at least one sublist, which is also non-empty, and the current element (x) matches the head of the sublist (y), prepend x to the sublist, otherwise prepend a new sublist to the state (xss) consisting solely of x. Each sublist is a group of equal, adjacent elements.
Suppose I have two lists:
val a = List('a', 'b', 'c')
val b = List('a', 'b', 'c', 'd')
I want to get the element which is not in the first list (in this case it's 'd'). I know I can do this with a loop, but is there any fancy functional way to do this quickly in one line?
I've been looking at the Scala List API, but could only found union and intersection (which will give me List('a', 'b', 'c', 'd') and List('a', 'b', 'c') respectively)
You can use diff for this:
scala> b diff a
res1: List[Char] = List(d)
You probably want to work with Set if you are doing diff.
I think you can use b -- a. Here is the documentation from scala:
def -- [B >: A] (that: List[B]) : List[B]
Computes the difference between this list and the given list that.
that
the list of elements to remove from this list.
returns this list without the elements of the given list that.
deprecated: use list1 filterNot (list2 contains) instead
Sorry for the deprecated method, here is the current good one: list1 filterNot (list2 contains)
def filterNot (p: (A) ⇒ Boolean) :
List[A] Selects all elements of this
list which do not satisfy a predicate.
p the predicate used to test elements.
returns a new list consisting of all
elements of this list that do not
satisfy the given predicate p. The
order of the elements is preserved.
definition classes: TraversableLike
Of course, this can be done in many ways. For flat structures like list of numbers and strings diff is the most elegant. Other ways are,
val ans1 = for { x <- b if !a.contains(x) } yield x
val ans2 = for { x <- b if !a.exists(_ == x) } yield x
val ans3 = b filterNot (x => b.contains(x) )
val ans4 = b diff a