Is there a way to find if a sequence of two chars are found in a list only if they are consecutive? - functional-programming

I am currently working in the elm syntax. An example would be like this:
(Sequence ('a') ('b')) ('c') ['a', 'b', 'c', 'd'] . In this example, i only test if the elements 'a', 'b', 'c' are members of the list. If yes, then i partition it and obtain (['a','b','c'],['d'])
I encountered problems in the following case:
(Sequence ('a') ('b')) ('c') ['a', 'b', 'c', 'a']
obtaining the result :
(['a','b','c','a'],[])
My question is: what condition should i put such that the elements 'a' and 'b' must be consecutive avoiding the case when they are matched alone?

This answer assumes that if you have Sequence 'a' 'b' 'c' and test it against the list ['a', 'b', 'c', 'a'], you want to receive the result (['a', 'b', 'c'], ['a']) (as asked in this comment).
In pseudo-code:
Split the list into two, list1 and list2. list1 should have the same length as your sequence. Elm provides List.take and List.drop for that
Convert your sequence into a list list_sequence with a helper function
Test if list1 and list_sequence are equal
If they are, return the tuple (list1, list2)
And here is the actual Elm code:
https://ellie-app.com/bjBLns4dKkra1

Here is some code that tests if a sequence of elements occurs in a list:
module Main exposing (main)
import Html exposing (Html, text)
containsSeq : List a -> List a -> Bool
containsSeq seq list =
let
helper remainingSeq remainingList savedSeq savedList =
case remainingSeq of
[] ->
True
x :: xs ->
case remainingList of
[] ->
False
y :: ys ->
if x == y then
helper xs ys (savedSeq ++ [ x ]) (savedList ++ [ y ])
else
case savedList of
[] ->
helper (savedSeq ++ remainingSeq) ys [] []
y2 :: y2s ->
helper (savedSeq ++ remainingSeq) (y2s ++ remainingList) [] []
in
helper seq list [] []
main =
text <| Debug.toString <| containsSeq [ 'a', 'b', 'c' ] [ 'a', 'b', 'a', 'b', 'c', 'd' ]
This only checks if the sequences appears and the type of the elements have to be comparable.
Here is the above function altered to return a partitioning of the old list as a 3 elements Tuple with (elementsBefore, sequence, elementsAfter). The result is wrapped in a Maybe so that if the sequence is not found, it returns Nothing.
module Main exposing (main)
import Html exposing (Html, text)
partitionBySeq : List a -> List a -> Maybe ( List a, List a, List a )
partitionBySeq seq list =
let
helper remainingSeq remainingList savedSeq savedCurrentList savedOldList =
case remainingSeq of
[] ->
Just ( savedOldList, seq, remainingList )
x :: xs ->
case remainingList of
[] ->
Nothing
y :: ys ->
if x == y then
helper xs ys (savedSeq ++ [ x ]) (savedCurrentList ++ [ y ]) savedOldList
else
case savedCurrentList of
[] ->
helper (savedSeq ++ remainingSeq) ys [] [] (savedOldList ++ [ y ])
y2 :: y2s ->
helper (savedSeq ++ remainingSeq) (y2s ++ remainingList) [] [] (savedOldList ++ [ y ])
in
helper seq list [] [] []
main =
text <| Debug.toString <| partitionBySeq [ 'a', 'b', 'c' ] [ 'a', 'b', 'a', 'b', 'c', 'd' ]
Of course, if you are only dealing with characters, you might as well convert the list into a String using String.fromList and use String.contains "abc" "ababcd" for the first version and String.split "abc" "ababcd" to implement the second one.

Related

A function that compare a two lists of string

I am a new at F# and i try to do this task:
Make a function compare : string list -> string list -> int that takes two string lists and returns: -1, 0 or 1
Please help. I spend a lot of time, and i can not understand how to implement this task.
Given the task I assume what your professor wants to teach you with this exercise. I'll try to give you a starting point without
Confusing you
Presenting a 'done-deal' solution
I assume the goal of this task is to work with recursive functions and pattern matching to element-wise compare their elements. It could looks somewhat like this here
open System
let aList = [ "Apple"; "Banana"; "Coconut" ]
let bList = [ "Apple"; "Banana"; "Coconut" ]
let cList = [ "Apple"; "Zebra" ]
let rec doSomething f (a : string list) (b : string list) =
match (a, b) with
| ([], []) ->
printfn "Both are empty"
| (x::xs, []) ->
printfn "A has elements (we can unpack the first element as x and the rest as xs) and B is empty"
| ([], x::xs) ->
printfn "A is empty and B has elements (we can unpack the first element as x and the rest as xs)"
| (x::xs, y::ys) ->
f x y
printfn "Both A and B have elements. We can unpack them as the first elements x and y and their respective tails xs and ys"
doSomething f xs ys
let isItTheSame (a : string) (b : string) =
if String.Equals(a, b) then
printfn "%s is equals to %s" a b
else
printfn "%s is not equals to %s" a b
doSomething isItTheSame aList bList
doSomething isItTheSame aList cList
The example has three different lists, two of them being equal and one of them being different. The doSomething function takes a function (string -> string -> unit) and two lists of strings.
Within the function you see a pattern match as well as a recursive call of doSomething in the last match block. The signatures aren't exactly what you need and you might want to think about how to change the parametrization for cases where you don't want to stop the recursion (the last match block - if the strings are equal you want to keep on comparing, right?).
Just take the code and try it out in FSI. I'm confident, that you'll find the solution 🙂
In F# many collections are comparable if their element type is:
let s1 = [ "a"; "b" ]
let s2 = [ "foo"; "bar" ]
compare s1 s2 // -5
let f1 = [ (fun () -> 1); fun () -> 2 ]
let f2 = [ (fun () -> 3); fun () -> 42 ]
// compare f1 f2 (* error FS0001: The type '(unit -> int)' does not support the 'comparison' constraint. *)
so
let slcomp (s1 : string list) s2 = compare s1 s2 |> sign
Posting for reference as the original question is answered already.

How to extract tuple from a datatype?

New to SML and trying to learn through a series of exercises. The function I am trying to write deals with flattening a tree with N children. My approach was to simply take the current NTreeNode and add its value to some list that I would return. Then take its second argument, the list of children, and tack that on to another list, which would be my queue. This queue would serve as all the items I still have left to process.
I tried to do this approach by passing the NTreeList and the list I would return with the initial value in flattenNTree, to a helper function.
However, when I try to process an NTreeNode from my queue it gives me back an NTree and I can't use my first/second functions on that, I need a tuple back from the queue. I just don't understand how to get back a tuple, I tried to use the NTreeNode constructor, but even that's giving me an NTree back.
My question is how can I extract a tuple from the NTree datatype I have defined.
datatype NTree =
NTreeNode of int * NTree list
| EmptyNTree
;
fun first (a, _) = a;
fun second (_, b) = b;
fun processTree queue finalList =
if null queue
then finalList
else processTree ((tl queue)#(second(NTreeNode(hd queue)))) finalList#[first (NTreeNode (hd queue)) ]
;
fun flattenNTree EmptyNTree = []
| flattenNTree (NTreeNode x) = processTree (second x) [(first x)]
;
An example input value:
val t =
NTreeNode (1, [
NTreeNode (2, [
NTreeNode (3, [EmptyNTree]),
NTreeNode (4, []),
NTreeNode (5, [EmptyNTree]),
EmptyNTree
]),
NTreeNode (6, [
NTreeNode (7, [EmptyNTree])
])
]);
It's much easier to take things apart with pattern matching than fiddling around with selectors like first or tl.
It's also more efficient to accumulate a list in reverse and fix that when you're finished than to repeatedly append to the end of it.
fun processTree [] final = reverse final
| processTree (EmptyTree::ts) final = processTree ts final
| processTree ((NTreeNode (v,t))::ts) final = processTree (ts # t) (v :: final)
Your processTree function is missing the case for EmptyNTree and you seem to be trying to add NTree constructors before calling first and second, whereas you need rather to strip them away, as you do in flattenNTree.
Both problems can be fixed by applying pattern matching to the head of the queue:
fun processTree queue finalList =
if null queue
then finalList
else case hd queue of
EmptyNTree => processTree (tl queue) finalList
| NTreeNode v => processTree (tl queue # second v) (finalList # [first v])
;
You might also consider an implementation based on list functionals (although the order of the result is not the same):
fun flattenNTree t = case t of
EmptyNTree => []
| NTreeNode (n, nts) => n :: (List.concat (List.map flattenNTree nts));
Given the tree type
datatype 'a tree = Node of 'a * 'a tree list
| Leaf
you can fold it:
fun fold f e0 Leaf = e0
| fold f e0 (Node (x, ts)) =
let val e1 = f (x, e0)
in foldl (fn (t, e2) => fold f e2 t) e1 ts
end
and flatten it:
fun flatten t =
fold op:: [] t

Filtering elements of one list by looking at boolean values from the second list

I have two lists of equal length. I want to filter the elements of the first list by looking, if the element, with the same index in the second list, has a true boolean value.
Example:
[1,2,3,4,5]:int list
[true,false,false,true,false]:bool list
Expected result: [1,4]
I know two ways I could achieve this:
1) Write a function that takes two lists. For every element in the first list, that I want to append, check if the current(head) element of the second list is true.
2) Zip the two lists and filter it according to the boolean value.
There should be an easier to go about this, right?
Not really. The cleanest way to do this is probably
List.map (fn (x,y) => x) (List.filter (fn (x,y) => y) (ListPair.zip (L1,L2)))
or
List.map Option.valOf (List.filter Option.isSome (ListPair.map(fn (x,y) => if y then SOME x else NONE) (L1,L2)))
The recursive function isn't too bad, either:
fun foo ([],[]) = []
| foo ([],L) = raise Fail "Different lengths"
| foo (L,[]) = raise Fail "Different lengths"
| foo (x::xs, b::bs) = if b then x::foo(xs,bs) else foo(xs,bs)
Those are pretty much the two options you have; either recurse two lists at once, or combine them into one list of tuples and recurse that. There are several combinators you could use to achieve the latter.
val foo = [1,2,3,4,5];
val bar = [true,false,true,true,false];
val pairs = ListPair.zip (foo, bar)
Once zipped, here are two other ways you can do it:
val result = List.foldr (fn ((n,b), res) => if b then n::res else res) [] pairs
val result = List.mapPartial (fn (n,b) => if b then SOME n else NONE) pairs
The simplest is probably
ListPair.foldr (fn (x,y,z) => if y then x :: z else z) [] (L1, L2)
Don't know if ML has list comprehension, but if your language has it:
[ x | (x, True) <- zip xs ys ]

SML Sum of List using option and Pattern matching

I'm creating sum of list and using option in it. When I pass an empty list, I should get NONE or else SOME value.
I'm able to do that in the following way:
fun sum_list xs =
case xs of
[] => NONE
| x =>
let
fun slist x =
case x of
[] => 0
| x::xs' => x + slist xs'
in
SOME (slist x)
end
But I want to do it in the other way round using pattern matching, in which I want to eval the result of sum_list to see whether it is NONE or contains some other value.
I have tried in various ways but I cannot get a hang of how to do in that way.
I think what you currently have is very clear and easy to understand.
If you want to avoid using slist, you have to call sum_list recursively on the tail of the list, pattern-match on that option value and return appropriate results:
fun sum_list xs =
case xs of
[] => NONE
| x::xs' => (case (sum_list xs') of
NONE => SOME x
| SOME y => SOME (x+y))

Case Statements and Pattern Matching

I'm coding in SML for an assignment and I've done a few practice problems and I feel like I'm missing something- I feel like I'm using too many case statements. Here's what I'm doing and the problem statements for what I'm having trouble with.:
Write a function all_except_option, which takes a string and a string list. Return NONE if the string is not in the list, else return SOME lst where lst is like the argument list except the string is not in it.
fun all_except_option(str : string, lst : string list) =
case lst of
[] => NONE
| x::xs => case same_string(x, str) of
true => SOME xs
| false => case all_except_option(str, xs) of
NONE => NONE
| SOME y=> SOME (x::y)
Write a function get_substitutions1, which takes a string list list (a list of list of strings, the substitutions) and a string s and returns a string list. The result has all the strings that are in some list in substitutions that also has s, but s itself should not be in the result.
fun get_substitutions1(lst : string list list, s : string) =
case lst of
[] => []
| x::xs => case all_except_option(s, x) of
NONE => get_substitutions1(xs, s)
| SOME y => y # get_substitutions1(xs, s)
-
same_string is a provided function,
fun same_string(s1 : string, s2 : string) = s1 = s2
First of all I would start using pattern matching in the function definition
instead of having a "top-level" case statement. Its basically boils down to the
same thing after de-sugaring. Also I would get rid of the explicit type annotations, unless strictly needed:
fun all_except_option (str, []) = NONE
| all_except_option (str, x :: xs) =
case same_string(x, str) of
true => SOME xs
| false => case all_except_option(str, xs) of
NONE => NONE
| SOME y => SOME (x::y)
fun get_substitutions1 ([], s) = []
| get_substitutions1 (x :: xs, s) =
case all_except_option(s, x) of
NONE => get_substitutions1(xs, s)
| SOME y => y # get_substitutions1(xs, s)
If speed is not of importance, then you could merge the two cases in the first function:
fun all_except_option (str, []) = NONE
| all_except_option (str, x :: xs) =
case (same_string(x, str), all_except_option(str, xs)) of
(true, _) => SOME xs
| (false, NONE) => NONE
| (false, SOME y) => SOME (x::y)
But since you are using append (#), in the second function, and since it is not
tail recursive, I don't believe that it your major concern. Keep in mind that
append is potential "evil" and you should almost always use concatenation (and
then reverse your result when returning it) and tail recursion when possible (it
always is).
If you really like the explicit type annotations, then you could do it like this:
val rec all_except_option : string * string list -> string list option =
fn (str, []) => NONE
| (str, x :: xs) =>
case (same_string(x, str), all_except_option(str, xs)) of
(true, _) => SOME xs
| (false, NONE) => NONE
| (false, SOME y) => SOME (x::y)
val rec get_substitutions1 : string list list * string -> string list =
fn ([], s) => []
| (x :: xs, s) =>
case all_except_option(s, x) of
NONE => get_substitutions1(xs, s)
| SOME y => y # get_substitutions1(xs, s)
But that is just my preferred way, if I really have to add type annotations.
By the way, why on earth do you have the same_string function? You can just do the comparison directly instead. Using an auxilary function is just wierd, unless you plan to exchange it with some special logic at some point. However your function names doesn't sugest that.
In addition to what Jesper.Reenberg mentioned, I just wanted to mention that a match on a bool for true and false can be replaced with an if-then-else. However, some people consider if-then-else uglier than a case statement
fun same_string( s1: string, s2: string ) = if String.compare( s1, s2 ) = EQUAL then true else false
fun contains( [], s: string ) = false
| contains( h::t, s: string ) = if same_string( s, h ) then true else contains( t, s )
fun all_except_option_successfully( s: string, [] ) = []
| all_except_option_successfully( s: string, h::t ) = if same_string( s, h ) then t else ( h :: all_except_option_successfully( s, t ) )
fun all_except_option( s: string, [] ) = NONE
| all_except_option( s: string, h::t ) = if same_string( s, h ) then SOME t else if contains( t, s ) then SOME ( h :: all_except_option_successfully( s, t ) ) else NONE

Resources