-
Notifications
You must be signed in to change notification settings - Fork 98
Expand file tree
/
Copy patharray-diff.js
More file actions
96 lines (87 loc) · 2.8 KB
/
array-diff.js
File metadata and controls
96 lines (87 loc) · 2.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Originally from https://www.npmjs.com/package/array-diff
// var _ = require('underscore')
var indexMap = function(list) {
var map = {}
list.forEach(function(each, i) {
map[each] = map[each] || []
map[each].push(i)
})
return map
}
var longestCommonSubstring = function(seq1, seq2) {
var result = {startString1:0, startString2:0, length:0}
var indexMapBefore = indexMap(seq1)
var previousOverlap = []
seq2.forEach(function(eachAfter, indexAfter) {
var overlapLength
var overlap = []
var indexesBefore = indexMapBefore[eachAfter] || []
indexesBefore.forEach(function(indexBefore) {
overlapLength = ((indexBefore && previousOverlap[indexBefore-1]) || 0) + 1;
if (overlapLength > result.length) {
result.length = overlapLength;
result.startString1 = indexBefore - overlapLength + 1;
result.startString2 = indexAfter - overlapLength + 1;
}
overlap[indexBefore] = overlapLength
})
previousOverlap = overlap
})
return result
}
var diff = function(before, after) {
var commonSeq = longestCommonSubstring(before, after)
var startBefore = commonSeq.startString1
var startAfter = commonSeq.startString2
if (commonSeq.length == 0) {
var result = before.map(function(each) { return ['-', each]})
return result.concat(after.map(function(each) { return ['+', each]}))
}
var beforeLeft = before.slice(0, startBefore)
var afterLeft = after.slice(0, startAfter)
var equal = after.slice(startAfter, startAfter + commonSeq.length)
.map(function(each) {return ['=', each]})
var beforeRight = before.slice(startBefore + commonSeq.length)
var afterRight = after.slice(startAfter + commonSeq.length)
return _.union(diff(beforeLeft, afterLeft), equal, diff(beforeRight, afterRight))
}
var orderedSetDiff = function(before, after) {
var diffRes = diff(before, after)
var result = []
diffRes.forEach(function(each) {
switch(each[0]) {
case '=':
result.push(each)
break
case '-':
result.push((after.indexOf(each[1]) > -1) ? ['x', each[1]] : ['-', each[1]])
break
case '+':
result.push((before.indexOf(each[1]) > -1) ? ['p', each[1]] : ['+', each[1]])
}
})
return result
}
var compress = function(diff) {
var result = []
var modifier
var section = []
diff.forEach(function(each) {
if(modifier && (each[0] == modifier)) {
section.push(each[1])
} else {
if(modifier) result.push([modifier, section])
section = [each[1]]
modifier = each[0]
}
})
if(modifier) result.push([modifier, section])
return result
}
function arrayDiff (opts) {
opts = opts || {}
return function(before, after) {
var result = opts.unique ? orderedSetDiff(before, after) : diff(before, after)
return opts.compress ? compress(result) : result
}
}