Scala генерировать уникальные пары из списка

Вход:

val list = List(1, 2, 3, 4)

Требуемый вывод:

Iterator((1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4))

Этот код работает:

for (cur1 <- 0 until list.size; cur2 <- (cur1 + 1) until list.size)
  yield (list(cur1), list(cur2))

но это не кажется оптимальным, есть ли лучший способ сделать это?

Ответ 1

Там встроен метод .combinations:

scala> List(1,2,3,4).combinations(2).toList
res0: List[List[Int]] = List(List(1, 2), List(1, 3), List(1, 4), List(2, 3), List(2, 4), List(3, 4))

Он возвращает Iterator, но я добавил .toList только для печати результата. Если вы хотите получить результаты в форме кортежа, вы можете сделать:

scala> List(1,2,3,4).combinations(2).map{ case Seq(x, y) => (x, y) }.toList
res1: List[(Int, Int)] = List((1,2), (1,3), (1,4), (2,3), (2,4), (3,4))

Вы также указали на уникальность, так что вы можете применить .distinct к вашему списку входных данных. Уникальность не является предварительным условием для вашей функции, потому что .combination не будет дедуксировать для вас.

Ответ 2

.combinations - это правильный способ создания уникальных произвольных групп любого размера, другое альтернативное решение, которое не проверяет единственность на первом месте, использует foldLeft таким образом:

val list = (1 to 10).toList

val header :: tail = list
tail.foldLeft((header, tail, List.empty[(Int, Int)])) {
  case ((header, tail, res), elem) =>
    (elem, tail.drop(1), res ++ tail.map(x => (header, x)))
}._3

Будет производить:

res0: List[(Int, Int)] = List((1,2), (1,3), (1,4), (1,5), (1,6), (1,7), (1,8), (1,9), (1,10), (2,3), (2,4), (2,5), (2,6), (2,7), (2,8), (2,9), (2,10), (3,4), (3,5), (3,6), (3,7), (3,8), (3,9), (3,10), (4,5), (4,6), (4,7), (4,8), (4,9), (4,10), (5,6), (5,7), (5,8), (5,9), (5,10), (6,7), (6,8), (6,9), (6,10), (7,8), (7,9), (7,10), (8,9), (8,10), (9,10))

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

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