下面給出的設置數據:反向笛卡爾乘積
a | b | c | d
1 | 3 | 7 | 11
1 | 5 | 7 | 11
1 | 3 | 8 | 11
1 | 5 | 8 | 11
1 | 6 | 8 | 11
執行反向笛卡爾乘積得到:
a | b | c | d
1 | 3,5 | 7,8 | 11
1 | 6 | 8 | 11
我目前使用Scala的工作,和我的輸入/輸出數據類型是目前:
ListBuffer[Array[Array[Int]]]
我想出了一個解決方案(見下文),但覺得它可以優化。我願意優化我的方法和全新的方法。在scala和c#中的解決方案是首選。
我也很好奇,如果這可以在MS SQL中完成。
我目前的解決方案:
def main(args: Array[String]): Unit = {
// Input
val data = ListBuffer(Array(Array(1), Array(3), Array(7), Array(11)),
Array(Array(1), Array(5), Array(7), Array(11)),
Array(Array(1), Array(3), Array(8), Array(11)),
Array(Array(1), Array(5), Array(8), Array(11)),
Array(Array(1), Array(6), Array(8), Array(11)))
reverseCartesianProduct(data)
}
def reverseCartesianProduct(input: ListBuffer[Array[Array[Int]]]): ListBuffer[Array[Array[Int]]] = {
val startIndex = input(0).size - 1
var results:ListBuffer[Array[Array[Int]]] = input
for (i <- startIndex to 0 by -1) {
results = groupForward(results, i, startIndex)
}
results
}
def groupForward(input: ListBuffer[Array[Array[Int]]], groupingIndex: Int, startIndex: Int): ListBuffer[Array[Array[Int]]] = {
if (startIndex < 0) {
val reduced = input.reduce((a, b) => {
mergeRows(a, b)
})
return ListBuffer(reduced)
}
val grouped = if (startIndex == groupingIndex) {
Map(0 -> input)
}
else {
groupOnIndex(input, startIndex)
}
val results = grouped.flatMap{
case (index, values: ListBuffer[Array[Array[Int]]]) =>
groupForward(values, groupingIndex, startIndex - 1)
}
results.to[ListBuffer]
}
def groupOnIndex(list: ListBuffer[Array[Array[Int]]], index: Int): Map[Int, ListBuffer[Array[Array[Int]]]] = {
var results = Map[Int, ListBuffer[Array[Array[Int]]]]()
list.foreach(a => {
val key = a(index).toList.hashCode()
if (!results.contains(key)) {
results += (key -> ListBuffer[Array[Array[Int]]]())
}
results(key) += a
})
results
}
def mergeRows(a: Array[Array[Int]], b: Array[Array[Int]]): Array[Array[Int]] = {
val zipped = a.zip(b)
val merged = zipped.map{ case (array1: Array[Int], array2: Array[Int]) =>
val m = array1 ++ array2
quickSort(m)
m.distinct
.array
}
merged
}
其工作原理是:
- 遍歷列,從右到左(該groupingIndex指定上運行其列此列是唯一一個爲了合併行而不必具有彼此相等的值)。
- 對所有其他列(不是groupingIndex)上的數據進行遞歸分組。
- 將所有列分組後,假定每個組中的數據在除分組列以外的每列中都有相同的值。
- 合併具有匹配列的行。爲每一列取不同的值並對每一列進行排序。
我很抱歉,如果這些沒有意義,我的大腦今天就不能運作。
答案必須是(1 | 3,5 | 7,8 | 11)聯合(1 | 6 | 8 | 11)還是與其他答案同樣好?ie(1 | 3,5 | 7 | 11)union(1 | 3,5,6 | 8 | 11),只要所有行都被覆蓋一次?要找到最佳答案實際上是一項非常艱鉅的任務,np-hard,請在這裏查看答案:https://cs.stackexchange.com/questions/87247/reverse-cartesian-product-matching-all-given-rows – jbilander