Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala distribution of lists with condition

So, it's very straigh forward, I have a list with nested lists, like so:

List(
*list1* List(List("n1", "n3"), List("n1", "n4"), List("n3", "n4")), 
*list2* List(List("n2"), List("n3"), List("n4"))
)

And I want to destribute the lists of the list1 with the lists of the list2, like so:

List(
List(List(n1, n3), List(n2)), 
List(List(n1, n4), List(n2)), 
List(List(n3, n4), List(n2)), 
List(List(n1, n3), List(n3)), 
List(List(n1, n4), List(n3)), 
List(List(n3, n4), List(n3)), 
List(List(n1, n3), List(n4)), 
List(List(n1, n4), List(n4)), 
List(List(n3, n4), List(n4))
)

This can be accomplished with the following function:

def combinationList[T](ls:List[List[T]]):List[List[T]] = ls match {
  case Nil => Nil::Nil
  case head :: tail => val rec = combinationList[T](tail)
    rec.flatMap(r => head.map(t => t::r))
}

The thing is, I want to add a condition where I only destribute lists where there are no duplicates, so the result would be:

List(
List(List(n1, n3), List(n2)), 
List(List(n1, n4), List(n2)), 
List(List(n3, n4), List(n2)),  
List(List(n1, n4), List(n3)),  
List(List(n1, n3), List(n4)), 
)

The closest I've got is by adding a filter and a contains before the mapping, but I still can't get the result, like so:

def combinationList[T](ls:List[List[T]]):List[List[T]] = ls match {
  case Nil => Nil::Nil
  case head :: tail => val rec = combinationList[T](tail)
    rec.flatMap(r => head.filter(x => !r.contains(x)).map(t => t::r))
}

The problem is that I think it's comparing the list as a whole and not the individual elements. Any ideas?

EDIT: I need to ignore duplicates within the function. I know it's possible to post-process the information and remove the ones with duplicates, but that's not what I'm looking for.

like image 831
Pedro Gonçalves Avatar asked Jan 23 '26 21:01

Pedro Gonçalves


1 Answers

You would need to decompose one level further to check the item existence, in a simplest form it can be as follow:

def combinationList[T](ls:List[List[List[T]]]) : List[List[List[T]]] = ls match {
    case head :: tail :: Nil =>
      for {
        hl <- head
        tl <- tail
        if !tl.forall(te => hl.contains(te))
      } yield List(hl, tl)
  }

It works on the assumption of input list having 2 sublists. I'm not sure what is the expectation of having 3 or more sublists in generic manner, it's all up to you to recursive further.

like image 84
Duong Nguyen Avatar answered Jan 26 '26 15:01

Duong Nguyen