14
14
package gnieh .diff
15
15
16
16
import scala .annotation .tailrec
17
-
18
- import scala .collection .SeqView
17
+ import scala .collection ._
19
18
20
19
/** Implementation of the patience algorithm [1] to compute the longest common subsequence
21
20
*
@@ -34,38 +33,20 @@ class Patience[T](withFallback: Boolean = true) extends Lcs[T] {
34
33
type Occurrence = (T , Int )
35
34
36
35
/** Returns occurrences that appear only once in the list, associated with their index */
37
- private def uniques (l : SeqView [T , IndexedSeq [T ]]): List [Occurrence ] = {
38
- @ tailrec
39
- def loop (idx : Int , acc : Map [T , Int ]): List [Occurrence ] =
40
- if (idx >= l.size) {
41
- acc.toList
42
- } else {
43
- val value = l(idx)
44
- if (acc.contains(value)) {
45
- // not unique, remove it from the accumulator and go further
46
- loop(idx + 1 , acc - value)
47
- } else {
48
- loop(idx + 1 , acc.updated(value, idx))
49
- }
50
- }
51
- loop(0 , Map ())
52
- }
36
+ private def uniques (l : SeqView [T , IndexedSeq [T ]]): List [Occurrence ] =
37
+ l.zipWithIndex.foldLeft(Map .empty[T , Int ]) {
38
+ case (acc, (value, idx)) =>
39
+ // if not unique, remove it from the accumulator and go further
40
+ if (acc.contains(value)) acc - value else acc.updated(value, idx)
41
+ }.toList
53
42
54
43
/** Takes all occurences from the first sequence and order them as in the second sequence if it is present */
55
44
private def common (l1 : List [Occurrence ], l2 : List [Occurrence ]): List [(Occurrence , Int )] = {
56
- @ tailrec
57
- def loop (l : List [Occurrence ], acc : List [(Occurrence , Int )]): List [(Occurrence , Int )] = l match {
58
- case occ :: tl =>
59
- // find the element in the second sequence if present
60
- l2.find(_._1 == occ._1) match {
61
- case Some ((_, idx2)) => loop(tl, (occ -> idx2) :: acc)
62
- case None => loop(tl, acc)
63
- }
64
- case Nil =>
65
- // sort by order of appearance in the second sequence
66
- acc sortWith (_._2 < _._2)
67
- }
68
- loop(l1, Nil )
45
+ val l2Indices : Map [T , Int ] = l2.map { case (t, idx) => t -> idx }(breakOut)
46
+ l1.foldLeft(List .empty[(Occurrence , Int )]) {
47
+ case (acc, occ @ (t, _)) =>
48
+ l2Indices.get(t).fold(acc)(idx => (occ -> idx) :: acc)
49
+ }.sortBy(_._2)
69
50
}
70
51
71
52
/** Returns the list of elements that appear only once in both l1 and l2 ordered as they appear in l2 with their index in l1 */
@@ -83,26 +64,28 @@ class Patience[T](withFallback: Boolean = true) extends Lcs[T] {
83
64
if (l.isEmpty) {
84
65
Nil
85
66
} else {
86
- @ tailrec
87
- def push (idx1 : Int , idx2 : Int , stacks : List [List [Stacked ]], last : Option [Stacked ], acc : List [List [Stacked ]]): List [List [Stacked ]] = stacks match {
88
- case (stack @ (Stacked (idx, _, _) :: _)) :: tl if idx > idx1 =>
89
- // we found the right stack
90
- acc.reverse ::: (Stacked (idx1, idx2, last) :: stack) :: tl
91
- case (stack @ (stacked :: _)) :: tl =>
92
- // try the next one
93
- push(idx1, idx2, tl, Some (stacked), stack :: acc)
94
- case Nil =>
95
- // no stack corresponds, create a new one
96
- acc.reverse ::: List (List (Stacked (idx1, idx2, last)))
97
- case Nil :: _ =>
98
- // this case should NEVER happen
99
- throw new Exception (" No empty stack must exist" )
100
- }
67
+
101
68
def sort (l : List [(Occurrence , Int )]): List [List [Stacked ]] =
102
69
l.foldLeft(List [List [Stacked ]]()) {
103
70
case (acc, ((_, idx1), idx2)) =>
104
- push(idx1, idx2, acc, None , Nil )
71
+
72
+ @ tailrec
73
+ def push (stacks : List [List [Stacked ]], last : Option [Stacked ], acc : List [List [Stacked ]]): List [List [Stacked ]] =
74
+ stacks match {
75
+ case (stack @ (Stacked (idx, _, _) :: _)) :: tl if idx > idx1 =>
76
+ // we found the right stack
77
+ acc.reverse ::: (Stacked (idx1, idx2, last) :: stack) :: tl
78
+ case (stack @ (stacked :: _)) :: tl =>
79
+ // try the next one
80
+ push(tl, Some (stacked), stack :: acc)
81
+ case Nil =>
82
+ // no stack corresponds, create a new one
83
+ acc.reverse ::: List (List (Stacked (idx1, idx2, last)))
84
+ }
85
+
86
+ push(acc, None , Nil )
105
87
}
88
+
106
89
val sorted = sort(l)
107
90
// this call is safe as we know that the list of occurrence is not empty here and that there are no empty stacks
108
91
val greatest = sorted.last.head
0 commit comments