SML: get index of item in list - list

I'm new to SML and I'm attempting to get the index of an item in a list. I know that using List.nth will give me the value of an item at a index position, but I want the index value. There may even be a built in function that I'm not aware of. In my case, the list will not contain duplicates so if the item is in the list I get the index, if not it returns ~1. Here is the code I have so far. It works, but I don't think it is very clean:
val L=[1,2,3,4,5];
val m=length L-1;
fun Index(item, m, L)=if m<0 then ~1 else
if List.nth(L, m)=item then m else Index(item,m-1,L);

To elaborate on my previous comment, I suggest some changes for an implementation that fits better in the ML idiom:
fun index(item, xs) =
let
fun index'(m, nil) = NONE
| index'(m, x::xr) = if x = item then SOME m else index'(m + 1, xr)
in
index'(0, xs)
end
The individual changes are:
Have index return a value of type int option. NONE means the item is not in the list, SOME i means it is in the list, and the index of its first occurrence is i. This way, no special values (~1) need be used and the function's intended usage can be inferred from its type.
Hide the parameter m by renaming the function to index' and wrapping it into an outer function index that calls it with the appropriate arguments. The prime character (`) often indicates auxiliary values.
Use pattern matching on the list to get to the individual elements, eliminating the need for List.nth.
Also note that most commonly, function and variable names begin with a lowercase letter (index rather than Index), while capital letters are used for constructor constants (SOME) and the like.

I would like to propose a simpler and less efficient version of this index function. I agree that it is not as desirable to use exceptions rather than int option, and that it is not tail-recursive. But it is certainly easier to read and thus may serve as learning material:
fun index (x, []) = raise Subscript
| index (x, y::ys) =
if x = y then 0 else 1 + index (x, ys)

fun index(list,n)=
= if n=0 then hd(list) else index(tl(list),n-1);
val index = fn : 'a list * int -> 'a
index([1,2,3,4,5],2);
val it = 3 : int
index([1,2,3,4,5],0);
val it = 1 : int

Related

Smallest sub-list that contains all numbers

I am trying to write a program in sml that takes in the length of a list, the max number that will appear on the list and the list of course. It then calculates the length of the smallest "sub-list" that contains all numbers.
I have tried to use the sliding window approach , with two indexes , front and tail. The front scans first and when it finds a number it writes into a map how many times it has already seen this number. If the program finds all numbers then it calls the tail. The tail scans the list and if it finds that a number has been seen more times than 1 it takes it off.
The code I have tried so far is the following:
structure Key=
struct
type ord_key=int
val compare=Int.compare
end
fun min x y = if x>y then y else x;
structure mymap = BinaryMapFn ( Key );
fun smallest_sub(n,t,listall,map)=
let
val k=0
val front=0
val tail=0
val minimum= n;
val list1=listall;
val list2=listall;
fun increase(list1,front,k,ourmap)=
let
val number= hd list1
val elem=mymap.find(ourmap,number)
val per=getOpt(elem,0)+1
fun decrease(list2,tail,k,ourmap,minimum)=
let
val number=hd list2
val elem=mymap.find(ourmap,number)
val per=getOpt(elem,0)-1
val per1=getOpt(elem,0)
in
if k>t then
if (per1=1) then decrease(tl list2,tail+1,k-1,mymap.insert(ourmap,number,per),min minimum (front-tail))
else decrease(tl list2,tail+1,k,mymap.insert(ourmap,number,per),min minimum (front-tail))
else increase (list1, front,k,ourmap)
end
in
if t>k then
if (elem<>NONE) then increase (tl list1,front+1,k,mymap.insert(ourmap,number,per))
else increase(tl list1,front+1,k+1,mymap.insert(ourmap,number,per))
else (if (n>front) then decrease(list2,tail,k,ourmap,minimum) else minimum)
end
in
increase(list1,front,k,map)
end
fun solve (n,t,acc)= smallest_sub(n,t,acc,mymap.empty)
But when I call it with this smallest_sub(10,3,[1,3,1,3,1,3,3,2,2,1]); it does not work. What have I done wrong??
Example: if input is 1,3,1,3,1,3,3,2,2,1 the program should recognize that the parto of the list that contains all numbers and is the smallest is 1,3,3,2 and 3,2,2,1 so the output should be 4
This problem of "smallest sub-list that contains all values" seems to recur in
new questions without a successful answer. This is because it's not a minimal,
complete, and verifiable example.
Because you use a "sliding window" approach, indexing the front and the back
of your input, a list taking O(n) time to index elements is not ideal. You
really do want to use arrays here. If your input function must have a list, you
can convert it to an array for the purpose of the algorithm.
I'd like to perform a cleanup of the code before answering, because running
your current code by hand is a bit hard because it's so condensed. Here's an
example of how you could abstract out the book-keeping of whether a given
sub-list contains at least one copy of each element in the original list:
Edit: I changed the code below after originally posting it.
structure CountMap = struct
structure IntMap = BinaryMapFn(struct
type ord_key = int
val compare = Int.compare
end)
fun count (m, x) =
Option.getOpt (IntMap.find (m, x), 0)
fun increment (m, x) =
IntMap.insert (m, x, count (m, x) + 1)
fun decrement (m, x) =
let val c' = count (m, x)
in if c' <= 1
then NONE
else SOME (IntMap.insert (m, x, c' - 1))
end
fun flip f (x, y) = f (y, x)
val fromList = List.foldl (flip increment) IntMap.empty
end
That is, a CountMap is an int IntMap.map where the Int represents the
fixed key type of the map, being int, and the int parameter in front of it
represents the value type of the map, being a count of how many times this
value occurred.
When building the initialCountMap below, you use CountMap.increment, and
when you use the "sliding window" approach, you use CountMap.decrement to
produce a new countMap that you can test on recursively.
If you decrement the occurrence below 1, you're looking at a sub-list that
doesn't contain every element at least once; we rule out any solution by
letting CountMap.decrement return NONE.
With all of this machinery abstracted out, the algorithm itself becomes much
easier to express. First, I'd like to convert the list to an array so that
indexing becomes O(1), because we'll be doing a lot of indexing.
fun smallest_sublist_length [] = 0
| smallest_sublist_length (xs : int list) =
let val arr = Array.fromList xs
val initialCountMap = CountMap.fromList xs
fun go countMap i j =
let val xi = Array.sub (arr, i)
val xj = Array.sub (arr, j)
val decrementLeft = CountMap.decrement (countMap, xi)
val decrementRight = CountMap.decrement (countMap, xj)
in
case (decrementLeft, decrementRight) of
(SOME leftCountMap, SOME rightCountMap) =>
Int.min (
go leftCountMap (i+1) j,
go rightCountMap i (j-1)
)
| (SOME leftCountMap, NONE) => go leftCountMap (i+1) j
| (NONE, SOME rightCountMap) => go rightCountMap i (j-1)
| (NONE, NONE) => j - i + 1
end
in
go initialCountMap 0 (Array.length arr - 1)
end
This appears to work, but...
Doing Int.min (go left..., go right...) incurs a cost of O(n^2) stack
memory (in the case where you cannot rule out either being optimal). This is a
good use-case for dynamic programming because your recursive sub-problems have a
common sub-structure, i.e.
go initialCountMap 0 10
|- go leftCountMap 1 10
| |- ...
| `- go rightCountMap 1 9 <-.
`- go rightCountMap 0 9 | possibly same sub-problem!
|- go leftCountMap 1 9 <-'
`- ...
So maybe there's a way to store the recursive sub-problem in a memory array and not
perform a recursive lookup if you know the result to this sub-problem. How to
do memoization in SML is a good question in and of itself. How to do purely
functional memoization in a non-lazy language is an even better one.
Another optimization you could make is that if you ever find a sub-list the
size of the number of unique elements, you need to look no further. This number
is incidentally the number of elements in initialCountMap, and IntMap
probably has a function for finding it.

2d matrix sml inserting to list - simple code

I have an sml-nj project in which I want to work with a 'list of lists' structure, which has "Squares". I'm trying to insert values to the list of lists recursively, but I still haven't understood how to insert elements to a 2d list.
Note - I CAN'T USE 'REF', ONLY http://smlfamily.org/Basis/list.html#SIG:LIST.app:VAL these functions.
datatype SquareContent = Mine | Digit of int | Blank;
datatype Square = Revealed of SquareContent | Concealed of SquareContent;
fun createMineSweeperGrid (n:int)
:(Square list list)=
let
fun createMines (rowCounter:int, colCounter:int
, retGame:Square list list):(Square list list) =
if rowCounter=n then
retGame (* finished all rows, should be n lists of size n*)
else
if colCounter=n then (*finished current row, move on*)
createMines (rowCounter+1, 0, mines,retGame)
else
let
val squareToInsert = Concealed(Mine) (* I wish to insert 'squareToInsert'
to retGame[rowCounter][colCounter], it's done dynamically, but I don't know
how to do that *)
in
createMines (rowCounter, colCounter+1, retGame)
end
in
createMines (0,0,[])
end
I could insert any kind of Square, it's decided dynamically and here I gave example only of concealed Mine so you can help me.. HELP..?
The essential thing to recognize is that in Standard ML, you don't mutate existing structures; rather, you create new ones. (Standard ML does support mutable structures, via ref and its friends, but it's not something to do lightly, and I see that you've already — rightly — ruled it out.)
In general, therefore, inserting something into the middle of a linked list is pretty expensive: it requires "unwinding" the list to the point where you want to insert, then inserting the value, and lastly building a copy of everything you'd unwound. For example, here's a function that would insert a value x at index i of a list:
fun insert (x, 0, L) = x :: L
| insert (x, i, h :: t) = h :: insert (x, i - 1, t)
| insert (_, _, nil) = raise Subscript
Fortunately, your function is written so as to not have to insert anything into the middle of an already-built linked list; rather, if I understand correctly what it's trying to do, it always puts the new square at the beginning of the first list. So:
let
val squareToInsert = Concealed(Mine)
val topRow :: rest = retGame
in
createMines (rowCounter, colCounter+1, (squareToInsert::topRow)::rest)
end
Note that you'll also need to fix another bug, which is that you never actually create new rows: you have a comment about "finished current row, move on", but then it just proceeds exactly the same as if it were still in the same row (just resetting the numbers as if it had moved to a new row). To fix this, use [] :: retGame when you want to add a new row at the top, and use [[]] instead of [] for the initial board (so that it starts out with an empty row).

Writing multiple functions in SML - Sequential Composition

I would like to understand how sequential composition works much better than I do now in SML. I have to write a program that takes a list of integers and moves the integer at index zero to the last index in the list. ie. [4, 5, 6] -> [5, 6, 4].
The code I have right now is:
- fun cycle3 x =
= if length(x) = 1 then x
= else (List.drop(x, 1);
= x # [hd(x)]);
val cycle3 = fn : 'a list -> 'a list
The question lies in my else statement, what I want to happen is first concatenate the first term to the end, and then second drop the first term. It seems simple enough, I just don't understand how to perform multiple functions in a particular order using SML. My understanding was that the first function called has the scope of the second function that would have the scope of the third function.. etc etc.. What am I doing wrong here?
Most things in SML are immutable -- your function, rather than modifying the list, is building a new list. List.drop(x,1) evaluates to a new list consisting of all but the first element of x, but does not modify x.
To use your method, you would bind the result of List.drop(x,1) to a variable, as in the following:
fun cycle3 x = if length x = 1
then x
else let
val y = List.drop(x,1)
in
y # [hd(x)]
end
Alternately, a cleaner way of doing this same thing, that also handles the possibility of an empty list:
fun cycle3 [] = []
| cycle3 (x::xs) = xs # [x]

Move items up in a list

How do you move items up in a list.
The input list would look like: let list = [1;2;3;4;5]
And the output list would look like one of the following:
[1;2;3;5;4]
.........>
[2;1;3;4;5]
...>......
Plot twist: I want to be able to move any index in the list up
From what I understand is this not something you aim to do with F# or functional languages, but it's a must have on my program.
I believe this can be done using both recursions and higher order(HO) functions, but since my knowlegde with HO's are very limited I tried to solve this using a recursion.
My approach to moving down an item in the list included a simple recursion with index and list as arguments like so:
let rec moveDownAt index list =
match index, list with
| -1, _ -> list
| 0, h1::h2::t -> h2::h1::t
| index, h::t -> h::moveDownAt (index - 1) t
| _, [] -> list
However, to move in the other direction I would need to reference the previous "head" and I assume I would have issues on the third match line | index, h::t -> h::moveDownAt (index - 1) t where i perform h:: since I add the head to the list (which would be the previous the next call if I add that argument).
Switching place on two elements means that one is moving up, and one is moving down.
Simple using the following code will solve the problem:
let moveUpAt index list = moveDownAt (index-1) list
This will displace the index making "index to be moved down" turn into "index to be moved up".
The basic idea is the following: First, return the nth element of the list. Then append the rest elements, except the nth element since you have already returned it. Here's the code:
let MoveToTop index xs =
List.nth xs index // take nth item
:: // and prepend it to the beginning of the
// original list, except the nth element
(
xs // original data
|> List.mapi
(fun i x -> i, x) // associate each element with its ordinal index
|> List.filter
(fun (i, _) -> i <> index) // allow only the elements whose index
// is not equal to requested index
|> List.map snd // remove the index from the data
// as we no longer need it
)
// test
[1; 2; 3; 4; 5]
|> MoveToTop 1 // don't forget, the index is zero-based
|> printfn "%A"
// output: [2; 1; 3; 4; 5]
Note that if index is outside the length of the list, an ArgumentException will be thrown.
A recursive algorithm is also possible, but it would be certainly less performant due to creation of excessive data and performing excessive computations.

How to use a tuple's elements as indexes to reach a list's elements-haskell

I have a list of tuples, which I am trying to use its elements to reach a nested list's elements.
list = [["c","a","b"],["k","l","m"]]
indexTuple = [(0,1),(1,1),(1,2)]
this way I need to check whether there is an "a" in one of the elements of the list corresponding to my indexTuple's elements. My attempt so far;
seekinga :: [[[Char]]] -> Int -> Int -> Int -> [(Int,Int)]
seekinga list x y width
| list !!(map fst indexTuple) !!(map snd indexTuple) == "a" = [(fst indexTuple,snd indexTuple)]
| otherwise = [()]
where indexTuple = [(x,y) | x <- [x-width..x+width], y <- [y-width..y+width]]
this obviously does not work, because the !! operator wants integers to work on, but map returns lists. Any suggestions are very much appreciated.
You really have two separate concerns: given two numbers, how do you index into a nest list and how do you get two numbers out of a tuple.
The first problem is easy to solve just by looking at types. You know how to index into one list: (!!) :: [a] -> Int -> a. Here, a can be anything, including a nested list. So, given [[[Char]]], we can use !! to get a [[Char]]. And, since this is a list itself, we can use !! again to get a [Char]. ([Char] is just String, in case you don't realize.)
So all we need to do here is use !! then use it again on the result of the first one.
Now, how do we actually get the two numbers out? This is where we use pattern matching. We can just match against a tuple with a let statement:
let (i, j) = tuple in ...
Now just put the two together and you're set.
So you can view an element with:
> list !! 1 !! 2
"m"
So lets make this a function:
:set -XNoMonomorphismRestriction
> let index lst i j= lst !! i !! j
And lets filter out those indexs which do not point to "a"
> filter (\(i, j) -> index list i j == "a") indexTuple
[(0,1)]
If instead
list = [["c","a","b"],["k","l","a"]]
then
> filter (\(i, j) -> index list i j == "a") indexTuple
[(0,1),(1,2)]
Using !! may not be your best option however, in fact it probably is not. I tried to break out the two parts of the problem, as I understood it, access the element and filter for indexes.