Сведение набора пар множеств к одной паре множеств

StackOverflow https://stackoverflow.com//questions/20005425

Вопрос

У меня есть for-comprehension с генератором от Set[MyType] Этот MyType имеет lazy val вызываемая переменная factsPair который возвращает пару наборов:(Установите[MyFact], установите[MyFact]).

Я хочу перебрать их все и объединить факты в одну сглаженную пару (Set[MyFact], Set[MyFact]) следующим образом, однако я получаю No implicit view available ... и not enough arguments for flatten: implicit (asTraversable ... ошибки.(Я немного новичок в Scala, поэтому все еще пытаюсь привыкнуть к ошибкам).

lazy val allFacts  =
(for {
  mytype <- mytypeList
} yield mytype.factsPair).flatten

Что мне нужно указать для сглаживания, чтобы это сработало?

Это было полезно?

Решение

Вы не сможете использовать flatten для этого, потому что flatten on a collection возвращает коллекцию, а кортеж - это не коллекция.

Конечно, вы можете просто разделить, выровнять и снова соединить:

val pairs = for {
  mytype <- mytypeList
} yield mytype.factsPair
val (first, second) = pairs.unzip
val allFacts = (first.flatten, second.flatten)

Другие советы

Scala flatten работает с теми же типами.У вас есть Seq[(Set[MyFact], Set[MyFact])], который нельзя сгладить.

Я бы порекомендовал изучить foldLeft функция, потому что она очень общая и довольно проста в использовании, как только вы освоитесь с ней:

lazy val allFacts = myTypeList.foldLeft((Set[MyFact](), Set[MyFact]())) {
  case (accumulator, next) =>
    val pairs1 = accumulator._1 ++ next.factsPair._1
    val pairs2 = accumulator._2 ++ next.factsPair._2
    (pairs1, pairs2)
}

Первый параметр принимает начальный элемент, к которому будут добавлены другие элементы.Мы начинаем с пустого Tuple[Set[MyFact], Set[MyFact]] инициализируется следующим образом: (Set[MyFact](), Set[MyFact]()).

Далее мы должны указать функцию, которая принимает накопитель и добавляет к нему следующий элемент и возвращает с новым накопителем, в котором есть следующий элемент.Из-за всех этих кортежей это выглядит некрасиво, но работает.

Кортеж недоступен для перемещения, поэтому вы не можете сгладить его.Вам нужно вернуть что-то, по чему можно повторять, например, список:

List((1,2), (3,4)).flatten          // bad
List(List(1,2), List(3,4)).flatten  // good

Я хотел бы предложить более алгебраический взгляд.То, что у вас здесь есть, может быть легко решено с помощью моноиды.Для каждого моноида существует нулевой элемент и операция объединения двух элементов в один.

В этом случае задается для моноида:нулевой элемент - это пустое множество, а операция - объединение.И если у нас есть два моноида, то их декартово произведение также является моноидом, где операции определены попарно (см. примеры в Википедии).

Scalaz определяет моноиды как для наборов, так и для кортежей, поэтому нам не нужно ничего там делать.Нам просто понадобится вспомогательная функция, объединяющая несколько моноидных элементов в один, которая легко реализуется с помощью folding:

def msum[A](ps: Iterable[A])(implicit m: Monoid[A]): A =
  ps.foldLeft(m.zero)(m.append(_, _))

(возможно, в Scala уже есть такая функция, я ее не нашел).С помощью msum мы можем легко определить

def pairs(ps: Iterable[MyType]): (Set[MyFact], Set[MyFact]) =
  msum(ps.map(_.factsPair))

использование неявных моноидов Scalaz для кортежей и множеств.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top