Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Union of two sets in Scala

From the question linked here, I found this implementation of Union in Scala:

def union(a: Set, b: Set): Set = i => a(i) || b(i)

And Set is a function of type:

type Set = Int => Boolean

Now I understand that in Scala, a function is mapped from Int to Boolean here, and I further understand how this statement is executed:

a(i) || b(i)

But what I don't understand is what is 'i' here. Where does it come from? And when it finds a match between to sets, it returns true, if it indeed does, where do I filter it?

like image 725
user1343318 Avatar asked Oct 06 '13 01:10

user1343318


People also ask

What is Union in Scala?

As the name suggests, a Union Type denotes a type that is the union of two or more types. For example, we can define a union type of Int and String values and use it as a parameter of a function that expects either an integer or string value as input. Scala is a strongly and statically typed language.

Which operator should you use to take the intersection of two sets in Scala?

The intersect() method is utilized to compute the intersection between two sets. Return Type: It returns a set containing the elements present in both the sets.

What does ++ mean in Scala?

++= can mean two different things in Scala: 1: Invoke the ++= method. In your example with flatMap , the ++= method of Builder takes another collection and adds its elements into the builder. Many of the other mutable collections in the Scala collections library define a similiar ++= method.

Is a Set immutable in Scala?

There are two kinds of Sets, the immutable and the mutable. The difference between mutable and immutable objects is that when an object is immutable, the object itself can't be changed. By default, Scala uses the immutable Set.


3 Answers

The Set (which is just a function) that gets returned from union takes some integer as a parameter; you must give it an arbitrary name so that you can refer to it in the function body. It may make more sense if you write the function like this:

def union(a: Set, b: Set): Set = {
  (i) => a(i) || b(i)
}

It may make even more sense if you write it like this:

def union(a: Set, b: Set): Set = {
  // The union of two sets is a new function that takes an Int...
  def theUnion(i: Int): Boolean = {
    // and returns true if EITEHR of the other functions are true
    a(i) || b(i)
  }

  // Now we want to return the NEW function
  theUnion
}

Again, i is arbitrary and could be replaced with any variable:

def union(a: Set, b: Set): Set = item => a(item) || b(item)

[Update]

Because we're representing sets as functions, there's no need to iterate to see if they contain a number. For example, here's a set that contains any number below -5:

val belowNegFive: Set = (i) => i < -5

When we call that function with a number, it will tell us if that number is in the set. Note that at no time did we actually tell it the specific numbers that were in the set:

scala> belowNegFive(10)
res0: Boolean = false

scala> belowNegFive(-100)
res1: Boolean = true

scala> belowNegFive(-1)
res2: Boolean = false

Here's another set that includes any number between 50 and 100:

val fiftyToHundred: Set = (i) => i >= 50 && i <= 100

scala> fiftyToHundred(50)
res3: Boolean = true

scala> fiftyToHundred(100)
res4: Boolean = true

scala> fiftyToHundred(75)
res5: Boolean = true

scala> fiftyToHundred(49)
res6: Boolean = false

Now, a union of the sets belowNegFive and fiftyToHundred would contain any number that is either below -5 or between 50 and 100. We can easily represent this in code by returning a new function which itself returns true if either of the other two functions returns true.

scala> val unionOfBoth: Set = (i) => belowNegFive(i) || fiftyToHundred(i)
unionOfBoth: Int => Boolean = <function1>

scala> unionOfBoth(-10)
res7: Boolean = true

scala> unionOfBoth(50)
res8: Boolean = true

scala> unionOfBoth(0)
res9: Boolean = false

The union function from your question is just a way of applying this pattern generically over any two sets.

like image 72
Michelle Tilley Avatar answered Oct 12 '22 05:10

Michelle Tilley


Let say we have object called SoSet given by

object SoSet {
    type Set = Int => Boolean
    val a : Set = ???
    val b : Set = ???
    def isItem(item : Int) = a(item) || b(item)
}

The signature of isItem is given by Int => Boolean which is a Set. So far so good.

But now we just want to return the function isItem (i.e. a Set).

So lets define union function for this (There are no parameters right now. We will add it later).

object SoSet {
    //..   
     def union : Set = isItem // returns the function isItem
}

Now lets refactor the isItem into a anonymous function.

object SoSet {
    //..   
    def union : Set = {
      (item : Int) => a(item) || b(item)
    }
}

Lets move Set a and b from object SoSet to parameters of def union. Refactor item to i.

object SoSet { 
   type Set = Int => Boolean
   def union(a : Set, b : Set) : Set = (i : Int) => a(i) || b(i)
}

UPDATE

 val s1 = Set(1, 2, 3)                           
 val s2 = Set(2, 3, 4)     
 val s3 = union(s1, s2) //  returns the function..  Int => Boolean = <function1>
 s3(2)  // invokes the function & checks if 2 is present in the union     
like image 23
Shrey Avatar answered Oct 12 '22 04:10

Shrey


And when it finds a match between to sets, it returns true, if it indeed does, where do I filter it?

union does not find a match between two sets, it creates a new set which contains the values of both sets. Example:

val a = (i) => i == 2 // a contains 2 as a(2) == True
val b = (i) => i == 5 // b contains 5 as b(5) == True
val u = union(a, b)   // u contains 2 and 5 as u(2) == True and u(5) == True

So the 'filtering' just happens on the way. This function is not iterating over each set, filtering specific things out, it just returns a combination of two functions which then can executed later to query for the actual values.

Example of querying the values of a union:

val a = (i) => i == 2
val b = (i) => i == 5
val u = union(a, b)

for(i <- 1 to 10 if u(i)) yield i     // returns Vector(2, 5)

And yes, this is not an optimal way of storing values in sets as you have to check values by guessing but it is a good way to demonstrate how combining functions adds complex functionality without writing very complex code.

like image 1
nemo Avatar answered Oct 12 '22 06:10

nemo