Datatype events = enter of string * real | exit of string *real;
So i have this Datatype and i have to write a function that takes a list of events as input and return that list sorted by the real part of events.
I tried to write some functions but didnt come up with anything good, any ideas?
this is the code i tried:
val rec ordina = fn
[] => []
|v1::v2::l => if (#2(v2)) > (#2(v1))
then ordina (v1::l)
else oridna (v2::1);
Errors i got:
poly: error: Can't find a fixed record type. Found near #2
poly: error: Can't find a fixed record type. Found near #2
Some feedback,
The datatype declaration should probably be
datatype event = Enter of string * real
| Exit of string * real
A single value contains a single event.
The plural is achieved by having a value of e.g. type event list.
Value constructors are usually written with an uppercase start letter.
In SML/NJ you have a generic sort function called ListMergeSort.sort. It takes a function with the type 'a * 'a -> bool where 'a = event in this case. You could then write a function,
fun cmp_event (event_a, event_b) = ...
that returns whether event_a should be ordered before event_b based on their real parts. Hint: First, make a helper function that extracts the real part. (Come up with a better name that reflects the purpose of the real part.)
fun get_real_part (Enter (_, r)) = ...
| get_real_part ... = ...
If you're not allowed to use ListMergeSort.sort, then make your own sort.
I am trying to delete the empty entries from a char list in sml.
This is my function but when I try to call it, it doesn't work and brings a fatal error.
fun no_spaces([]) = raise Empty
| no_spaces(e::f) = if(e = #" ") then no_spaces(f) else e::no_spaces(f);
no_spaces [#"a",#"a",#" ",#"d",#" "];
What am I doing wrong?
Thank you
P.S Or if this is not possible, then how can I delete empty spaces from a string?
I suspect that by raise Empty you meant to return the empty list rather than trigger a runtime error. You have indicated in the comments that you have fixed that particular bug, but it can't hurt to say a bit more about when you should return nil and when you should raise empty.
As a general rule of thumb, if you are defining a function which sends lists to lists and the output list is constructed by processing the elements of the input list one by one (e.g. return the list of even elements in an int list, which involves checking the parity of each element in turn) then your basis case should be something like fun f [] = [] because an empty input corresponds to nothing left to process, and if there is nothing left to process then there is nothing left to return.
But -- if the goal of the function on lists is to return an element of the list (such as the first even entry) then it is natural to raise Empty:
fun firstEven [] = raise Empty
| firstEven (x::xs) = if x mod 2 = 0 then x else firstEven xs;
Here raise Empty makes perfect: since [] doesn't contain any integer it doesn't contain a first even one to return. Thus, this is an error situation which (ideally) should be addressed with a handle somewhere in the calling function.
An argument could be made that raise Empty should never be used since SML provides an alternative error handling method which uses the option type constructor. The function firstEven could be rewritten
fun firstEven [] = NONE
| firstEven (x::xs) = if x mod 2 = 0 then SOME x else firstEven xs;
in this case the calling function would pattern match on the returned value(using the two patterns NONE and SOME x) rather than providing an exception handler. Conceptually this second approach is cleaner and possibly even more efficient (it seems to be in F#, see this, I'm not sure about SML).
See this for a discussion of the two error handling methods in SML.
I am trying to implement the following:
let list = [1;2;3;4];;
if ((List.exists 3 list) = true)
print_string "element exists in list\n"
But it is giving me the error: This expression has type int list
but an expression was expected of type 'a -> bool
I am not sure what this means.
List.exists takes a function and a list, not a value and a list. For testing whether a value is in a list, use List.mem.
Your if looks like C syntax. In OCaml you need to use then (but you don't need the parentheses).
As a side comment, if e = true then ... is the same as if e then .... If you use good names for things, the latter is usually clearer.
How to declare a function suffixsen : string list -> string list ?
After declaring types inside the parens, declare the function's return type on the outside with :return-type. At least in SMLnj. I found this through trial and error, can't find documentation for it.
fun suffixson (xs: string list ): string list =
map (fn x => x ^ "son") xs
The syntax to define a function with one argument in sml is:
fun functionName argumentName = functionBody
or
fun functionName (argumentName : argumentType) = functionBody
if you want to specify the type explicitly. So to define a function named suffixsen of type string list -> string list, you can do:
fun suffixsen (strings : string list) = someExpressionThatReturnsAStringList
Edit in response to you comment:
In order to append "son" to each string in the list, you should look at the ^ operator[1], which concatenates string, and the map function which performs an operation for each element in a list.
[1] http://www.standardml.org/Basis/string.html#SIG:STRING.^:VAL (copy and paste this link in your browser - for some reason I can't get this to be clickable)
I've got a list of objects List[Object] which are all instantiated from the same class. This class has a field which must be unique Object.property. What is the cleanest way to iterate the list of objects and remove all objects(but the first) with the same property?
list.groupBy(_.property).map(_._2.head)
Explanation: The groupBy method accepts a function that converts an element to a key for grouping. _.property is just shorthand for elem: Object => elem.property (the compiler generates a unique name, something like x$1). So now we have a map Map[Property, List[Object]]. A Map[K,V] extends Traversable[(K,V)]. So it can be traversed like a list, but elements are a tuple. This is similar to Java's Map#entrySet(). The map method creates a new collection by iterating each element and applying a function to it. In this case the function is _._2.head which is shorthand for elem: (Property, List[Object]) => elem._2.head. _2 is just a method of Tuple that returns the second element. The second element is List[Object] and head returns the first element
To get the result to be a type you want:
import collection.breakOut
val l2: List[Object] = list.groupBy(_.property).map(_._2.head)(breakOut)
To explain briefly, map actually expects two arguments, a function and an object that is used to construct the result. In the first code snippet you don't see the second value because it is marked as implicit and so provided by the compiler from a list of predefined values in scope. The result is usually obtained from the mapped container. This is usually a good thing. map on List will return List, map on Array will return Array etc. In this case however, we want to express the container we want as result. This is where the breakOut method is used. It constructs a builder (the thing that builds results) by only looking at the desired result type. It is a generic method and the compiler infers its generic types because we explicitly typed l2 to be List[Object] or, to preserve order (assuming Object#property is of type Property):
list.foldRight((List[Object](), Set[Property]())) {
case (o, cum#(objects, props)) =>
if (props(o.property)) cum else (o :: objects, props + o.property))
}._1
foldRight is a method that accepts an initial result and a function that accepts an element and returns an updated result. The method iterates each element, updating the result according to applying the function to each element and returning the final result. We go from right to left (rather than left to right with foldLeft) because we are prepending to objects - this is O(1), but appending is O(N). Also observe the good styling here, we are using a pattern match to extract the elements.
In this case, the initial result is a pair (tuple) of an empty list and a set. The list is the result we're interested in and the set is used to keep track of what properties we already encountered. In each iteration we check if the set props already contains the property (in Scala, obj(x) is translated to obj.apply(x). In Set, the method apply is def apply(a: A): Boolean. That is, accepts an element and returns true / false if it exists or not). If the property exists (already encountered), the result is returned as-is. Otherwise the result is updated to contain the object (o :: objects) and the property is recorded (props + o.property)
Update: #andreypopp wanted a generic method:
import scala.collection.IterableLike
import scala.collection.generic.CanBuildFrom
class RichCollection[A, Repr](xs: IterableLike[A, Repr]){
def distinctBy[B, That](f: A => B)(implicit cbf: CanBuildFrom[Repr, A, That]) = {
val builder = cbf(xs.repr)
val i = xs.iterator
var set = Set[B]()
while (i.hasNext) {
val o = i.next
val b = f(o)
if (!set(b)) {
set += b
builder += o
}
}
builder.result
}
}
implicit def toRich[A, Repr](xs: IterableLike[A, Repr]) = new RichCollection(xs)
to use:
scala> list.distinctBy(_.property)
res7: List[Obj] = List(Obj(1), Obj(2), Obj(3))
Also note that this is pretty efficient as we are using a builder. If you have really large lists, you may want to use a mutable HashSet instead of a regular set and benchmark the performance.
Starting Scala 2.13, most collections are now provided with a distinctBy method which returns all elements of the sequence ignoring the duplicates after applying a given transforming function:
list.distinctBy(_.property)
For instance:
List(("a", 2), ("b", 2), ("a", 5)).distinctBy(_._1) // List((a,2), (b,2))
List(("a", 2.7), ("b", 2.1), ("a", 5.4)).distinctBy(_._2.floor) // List((a,2.7), (a,5.4))
Here is a little bit sneaky but fast solution that preserves order:
list.filterNot{ var set = Set[Property]()
obj => val b = set(obj.property); set += obj.property; b}
Although it uses internally a var, I think it is easier to understand and to read than the foldLeft-solution.
A lot of good answers above. However, distinctBy is already in Scala, but in a not-so-obvious place. Perhaps you can use it like
def distinctBy[A, B](xs: List[A])(f: A => B): List[A] =
scala.reflect.internal.util.Collections.distinctBy(xs)(f)
With preserve order:
def distinctBy[L, E](list: List[L])(f: L => E): List[L] =
list.foldLeft((Vector.empty[L], Set.empty[E])) {
case ((acc, set), item) =>
val key = f(item)
if (set.contains(key)) (acc, set)
else (acc :+ item, set + key)
}._1.toList
distinctBy(list)(_.property)
One more solution
#tailrec
def collectUnique(l: List[Object], s: Set[Property], u: List[Object]): List[Object] = l match {
case Nil => u.reverse
case (h :: t) =>
if (s(h.property)) collectUnique(t, s, u) else collectUnique(t, s + h.prop, h :: u)
}
I found a way to make it work with groupBy, with one intermediary step:
def distinctBy[T, P, From[X] <: TraversableLike[X, From[X]]](collection: From[T])(property: T => P): From[T] = {
val uniqueValues: Set[T] = collection.groupBy(property).map(_._2.head)(breakOut)
collection.filter(uniqueValues)
}
Use it like this:
scala> distinctBy(List(redVolvo, bluePrius, redLeon))(_.color)
res0: List[Car] = List(redVolvo, bluePrius)
Similar to IttayD's first solution, but it filters the original collection based on the set of unique values. If my expectations are correct, this does three traversals: one for groupBy, one for map and one for filter. It maintains the ordering of the original collection, but does not necessarily take the first value for each property. For example, it could have returned List(bluePrius, redLeon) instead.
Of course, IttayD's solution is still faster since it does only one traversal.
My solution also has the disadvantage that, if the collection has Cars that are actually the same, both will be in the output list. This could be fixed by removing filter and returning uniqueValues directly, with type From[T]. However, it seems like CanBuildFrom[Map[P, From[T]], T, From[T]] does not exist... suggestions are welcome!
With a collection and a function from a record to a key this yields a list of records distinct by key. It's not clear whether groupBy will preserve the order in the original collection. It may even depend on the type of collection. I'm guessing either head or last will consistently yield the earliest element.
collection.groupBy(keyFunction).values.map(_.head)
When will Scala get a nubBy? It's been in Haskell for decades.
If you want to remove duplicates and preserve the order of the list you can try this two liner:
val tmpUniqueList = scala.collection.mutable.Set[String]()
val myUniqueObjects = for(o <- myObjects if tmpUniqueList.add(o.property)) yield o
this is entirely a rip of #IttayD 's answer, but unfortunately I don't have enough reputation to comment.
Rather than creating an implicit function to convert your iteratble, you can simply create an implicit class:
import scala.collection.IterableLike
import scala.collection.generic.CanBuildFrom
implicit class RichCollection[A, Repr](xs: IterableLike[A, Repr]){
def distinctBy[B, That](f: A => B)(implicit cbf: CanBuildFrom[Repr, A, That]) = {
val builder = cbf(xs.repr)
val i = xs.iterator
var set = Set[B]()
while (i.hasNext) {
val o = i.next
val b = f(o)
if (!set(b)) {
set += b
builder += o
}
}
builder.result
}
}