Распределение списков Scala с условием

Pedro Gonçalves спросил: 28 марта 2018 в 04:38 в: scala

Итак, это очень несложно, у меня есть список с вложенными списками, например:

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

И я хочу уничтожить списки list1 со списками list2 , например:

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))
)

Это может быть выполнено с помощью следующей функции:

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))
}

Дело в том, что я хочу добавить условие, когда я только списываю списки, где нет дубликатов, поэтому результат будет следующим:

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)), 
)

Ближайший я У меня есть добавление фильтра и содержит перед сопоставлением, но я все еще не могу получить результат, например:

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))
}

Проблема в том, что я думаю, что это сравнение списка в целом, а не отдельных элементов. Любые идеи?

EDIT: Мне нужно игнорировать дубликаты внутри функции. Я знаю, что можно постовать информацию и удалить дубликаты, но это не то, что я ищу.

2 ответа

Есть решение
Duong Nguyen ответил: 28 марта 2018 в 05:48

Вам нужно будет разложить еще один уровень, чтобы проверить существование элемента, в простейшей форме это может быть следующим образом:

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)
  }

Он работает в предположении, что список ввода имеет 2 списка Я не уверен, каково ожидание иметь 3 или более подсписка в общем виде, это все зависит от вас, чтобы рекурсивно дальше.

Pedro Gonçalves ответил: 28 марта 2018 в 05:59
Ваша функция получает List [List [List [T]] , но это не то, что получает моя, поэтому она не работает даже для моего примера.
Duong Nguyen ответил: 28 марта 2018 в 06:02
Ваш ввод определенно является List[List[List[T]]]. Должно быть ясно: либо два, если List[List[T]], либо List[List[List[T]]]. В конце концов, продемонстрированный код - это идеи.
Pedro Gonçalves ответил: 28 марта 2018 в 06:56
Я немного изменился, и я получил его на работу. Исходя из вашего решения, поэтому я отмечу как ответ. Если вы хотите знать,"!" должно быть до hl.contains (te) , а не там, где вы его положили. Независимо от того, ваше решение в значительной степени решило мою проблему, большое спасибо!
Pedro Gonçalves ответил: 28 марта 2018 в 08:03
Тем временем я решил это, добавив дополнительный регистр: case head :: Nil = > для (x < - head) yield List (x)
Dennis Hunziker ответил: 28 марта 2018 в 06:31

С текущим типом возвращаемого значения вам, вероятно, придется снова соответствовать, чтобы"просмотреть" список. Нечто подобное может сделать работу:

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 {
            case xx: List[_] => {
                val combined = (xx.map(List(_)) ++ r)
                combined.distinct == combined
        }
  }.map(t => t::r))
}