abstract class FinSet[T] protected () {
// given a set other, it returns true iff every element of this is an element of other
def <=(other:FinSet[T]): Boolean =
// ????
That is what I am given so far. I am somewhat confused on how to implement this method. Would I be calling the method like so:
Set(1,2,3).<=(Set(3,2,1)) which should return true
I was wondering if this would work, but it seems too simple:
def <=(other:FinSet[T]): Boolean = if (this == other) true else false
Just looking for some guidance. Thanks.
& - means intersection, if second set doesn't have elements from first set, the following code would return false.
(thisSet & thatSet) == thisSet
In details this code computes the intersection between this set and another set and checks if elements in this equal to result of the first expression.
see & or intersect(more verbose version) method in Scaladoc
You can also do something like this:
thisSet.forall(x => thatSet contains x)
or less verbose:
thisSet.forall(thatSet contains _)
or like this:
(thisSet ++ thatSet) == thatSet
or maybe like this:
(thatSet -- thisSet).size == (thatSet.size - thisSet.size)
Rephrasing the requirement: you want to check if, for all elements of this set, the other set contains the element.
This sounds like the combination of two more primitive functions that you will probably want anyway. So, if you haven't done so already, I would define the methods:
def forall(predicate: T => Boolean): Boolean // Checks that predicate holds for all elements
def contains(elem: T): Boolean // Check that elem is an element of the set
Then the method <= devolves to:
def <=(other: FinSet[T]): Boolean = forall(other.contains)
Related
I just discovered something weird. This statement:
Some("test this").contains("test")
Evaluates to false. While this evaluates to true:
Some("test this").contains("test this")
How does this make sense? I thought the Option would run the contains on the wrapped object if possible.
EDIT:
I'm also thinking about this from a code readability perspective. Imagine you are seeing this code:
person.name.contains("Roger")
Must name be equal to Roger? Or can it contain Roger? The behavior depends if it's a String or Option[String].
There's a principle in typed functional programming called "parametric reasoning". Broadly stated, the principle is that it's desirable to be able to have intuitions about what a function does just from looking at its type signature.
If we "devirtualize" (effectively turning it into a static method... this is actually a fairly common optimization step in object-oriented runtimes) Option's contains method has the signature:
def contains[A, A1 >: A](opt: Option[A], elem: A1): Boolean
That is, it takes an Option[A] and an A1 (where A1 is a supertype of A, if it's not an A) and returns a Boolean. Implicitly in Scala's typesystem, of course, we know that A and A1 are both subtypes of Any.
Without knowing anything more about what the types A and A1 are (A might be String and A1 might be AnyRef, or A and A1 might both be Int: whatever our intuition, it has to apply as much in either situation), what could we possibly do? We're basically limited to combinations of operations involving an Option[Any] and an Any which eventually get us to a Boolean (and, ideally, won't throw an exception).
For instance, opt.nonEmpty && opt.get == elem works: we can always call nonEmpty on an Option[Any] and then compare the contents using equality. We could also do something like opt.isEmpty || (opt.get.## % 43) == (elem.## % 57), but knowing that the contents of the Option and some other object have equal remainders in two different bases doesn't strike one as useful.
Note that in your specific case, because there's no contains method on an Any. What should the behavior be if we have an Option[Int]?
It might actually be useful, since we do have the ability to convert arbitrary objects into Strings via the toString method (thank you Java!), to implement a containsSubstring method on Option[A]:
def containsSubstring(substring: String): Boolean =
nonEmpty && get.toString.contains(substring)
You could implement an enrichment class along these lines:
object Enrichments {
implicit class OptionOps[A](opt: Option[A]) extends AnyVal {
def containsSubstring(substring: String): Boolean =
opt.nonEmpty && opt.get.toString.contains(substring)
}
}
then you only need:
import Enrichments.OptionOps
Some("test this").containsSubstring("test") // evaluates true
case class Person(name: Option[String], age: Int)
// Option(p).containsSubstring("Roger") would also work, assuming Person doesn't override toString...
def isRoger(p: Person): Boolean = p.name.containsSubstring("Roger")
I recommend to check the docs and eventually the code of the API that you are you using. The docs detail what Option's contains does and how it works:
/** Tests whether the option contains a given value as an element.
*
* This is equivalent to:
*
* option match {
* case Some(x) => x == elem
* case None => false
* }
*
* // Returns true because Some instance contains string "something" which equals "something".
* Some("something") contains "something"
*
* // Returns false because "something" != "anything".
* Some("something") contains "anything"
*
* // Returns false when method called on None.
* None contains "anything"
*
* #param elem the element to test.
* #return `true` if the option has an element that is equal (as
* determined by `==`) to `elem`, `false` otherwise.
*/
final def contains[A1 >: A](elem: A1): Boolean =
!isEmpty && this.get == elem
Why is the output of this comparison outputs true?
import scala.collection.immutable.ListSet
Set(1) == ListSet(1) // Expect false
//Output
res0: Boolean = true
And in a more general sense, how the comparison is actually done?
Since the inheritance chain Set <: GenSet <: GenSetLike is a bit lengthy, it might be not immediately obvious where to look for the code of equals, so I thought maybe I quote it here:
GenSetLike.scala:
/** Compares this set with another object for equality.
*
* '''Note:''' This operation contains an unchecked cast: if `that`
* is a set, it will assume with an unchecked cast
* that it has the same element type as this set.
* Any subsequent ClassCastException is treated as a `false` result.
* #param that the other object
* #return `true` if `that` is a set which contains the same elements
* as this set.
*/
override def equals(that: Any): Boolean = that match {
case that: GenSet[_] =>
(this eq that) ||
(that canEqual this) &&
(this.size == that.size) &&
(try this subsetOf that.asInstanceOf[GenSet[A]]
catch { case ex: ClassCastException => false })
case _ =>
false
}
Essentially, it checks whether the other object is also a GenSet, and if yes, it attempts to perform some fail-fast checks (like comparing size and invoking canEqual), and if the sizes are equal, it checks whether this set is a subset of another set, presumably by checking each element.
So, the exact class used to represent the set at runtime is irrelevant, what matters is that the compared object is also a GenSet and has the same elements.
From Scala collections equality:
The collection libraries have a uniform approach to equality and hashing. The idea is, first, to divide collections into sets, maps, and sequences.
...
On the other hand, within the same category, collections are equal if and only if they have the same elements
In your case, both collections are considered sets and they contain the same elements, hence, they're equal.
Scala 2.12.8 documentation:
This class implements immutable sets using a list-based data
structure.
So ListSet is a set too but with concrete (list-based) implementation.
I am relatively new to Scala functional programming. I have been following a few tasks, however, finding difficult to understand or implement the concept below.
Basically, I want write a function which takes a list and a function, and returns true if the function returns true for at least one
item in the list. An example would be: hasMatch(isEven,List(1,2,3,5)) will return true, but hasMatch(isEven,List(1,3,5)) will return false.
A sample solution or hint is provided with the problem, as seen below:
def hasMatch (fn:(Int)=>Boolean,lst:List[Int]):Boolean = {
lst.foreach ((x:Int) => if (fn(x)) return true)
return false
}
Could someone please explain the concept behind it or ways to implement it.
Your isEven function is going to determine the outcome of the hasMatch function. So assuming that your isEven function is defined like this:
def isEven(x: Int): Boolean = x % 2 == 0
You can now define your hasMatch function like this:
def hasMatch(fn: Int => Boolean, l: List[Int]): Boolean = {
l.exists(elem => fn(elem))
}
You then call the function like this:
hasMatch(isEven, List(1,2,3,5))
def hasMatch(fn: Int => Boolean, lst: List[Int]): Boolean = lst.exists(fn)
The exists function has the same semantics as what you're after - it returns true if fn returns true for at least one element, false otherwise.
The biggest problem with your implementation: return is a really bad thing in scala, and should (almost) never be used.
Also, there are more idiomatic ways to do what you want, rather than spelling out the imperative loop with foreach.
Here is one possibility:
def hasMatch[T](lst: List[T])(fn: T => Boolean) = lst.exists(fn)
I added a type parameter to your definition, so that it works for any type, not just Int. Also, I made fn the last argument, and moved it into a separate list. It makes it easier to pass anonymous functions in:
if (hasMatch(List(1,2,3,4,5)) { _ > 5 }) println("There are elements greater than five")
I want to know if a List is homogeneous.
Here is my code :
def isHomogeneous(ls: List[Any]) = ls.map(_.getClass).toSet.size == 1
Is there a better way ?
def allEqual(xs: Traversable[_]) =
xs.headOption.forall(head => xs.forall(_ == head))
def isHomogeneous(xs: Traversable[_]) =
allEqual(xs.view.map(_.getClass))
Keeps the getClass business separate from the traversal.
Uses more general type Traversable instead of List.
Works for Nil.
Does not traverse the entire collection unless necessary.
How about
def isHomogeneous(l: List[Any]) = {
val t = l(0).getClass
l.forall(_.getClass == t)
}
So if all elements have the same type as the first, it returns true
EDIT: To expand a bit on why I think this solution is better:
It only loops through the list once
It can exit early(If the second element is of a different class, it can immediately exit instead of trying other elements)
It does not create intermediate objects
It does not require a hashCode method to be implemented (Which it may, depending on the implementation of Set)
It looks, at least to me, clearer
I have the following Scala code snippet:
type Set = Int => Boolean
def contains(s: Set, element:Int): Boolean = s(element)
def singletonSet(element: Int): Set = Set(element)
val oneElementSet = singletonSet(5)
contains(oneElementSet, 5) // true
contains(oneElementSet, 6) // false
I'm trying to wrap my head around what this does: Set(element). Looks like it'll substitute element in place of an Int argument, to produce this: 5 => Boolean. There is no comparison anywhere, so why does oneElementSet(5) returns true, and oneElementSet(6) returns false?
Thanks!
Scala has separate namespaces for types and values. Your type alias defines what Set is in the type namespace, but in the definition of singletonSet Set comes from the value namespace, in fact it is the companion object scala.collection.immutable.Set. Set(element) invokes the apply method of the companion object, which returns a scala.collection.immutable.Set[Int], which turns out to be a subtype of Int => Boolean and therefore is a Set (your type alias) as well.