private static Lcs Backtrack(int[,] matrix, List <JToken> left, List <JToken> right, int li, int ri) { var result = new Lcs(); for (int i = li, j = ri; i > 0 && j > 0;) { // If the JSON tokens at the same position are both Objects or both Arrays, we just say they // are the same even if they are not, because we can package smaller deltas than an entire // object or array replacement by doing object to object or array to array diff. if (left[i - 1].Equals(right[j - 1]) || (left[i - 1].Type == JTokenType.Object && right[j - 1].Type == JTokenType.Object) || (left[i - 1].Type == JTokenType.Array && right[j - 1].Type == JTokenType.Array)) { result.Sequence.Insert(0, left[i - 1]); result.Indices1.Insert(0, i - 1); result.Indices2.Insert(0, j - 1); i--; j--; continue; } if (matrix[i, j - 1] > matrix[i - 1, j]) { j--; } else { i--; } } return(result); }
private static Lcs Backtrack(int[,] matrix, List <JToken> left, List <JToken> right, int li, int ri, ItemMatch match) { var result = new Lcs(); for (int i = 1, j = 1; i <= li && j <= ri;) { // If the JSON tokens at the same position are both Objects or both Arrays, we just say they // are the same even if they are not, because we can package smaller deltas than an entire // object or array replacement by doing object to object or array to array diff. if (match.Match(left[i - 1], right[j - 1])) { result.Sequence.Add(left[i - 1]); result.Indices1.Add(i - 1); result.Indices2.Add(j - 1); i++; j++; continue; } if (matrix[i, j - 1] > matrix[i - 1, j]) { i++; } else { j++; } } return(result); }
private JObject ArrayDiff(JArray left, JArray right) { var objectHash = this._options.ObjectHash; var itemMatch = new DefaultItemMatch(objectHash); var result = JObject.Parse(@"{ ""_t"": ""a"" }"); int commonHead = 0; int commonTail = 0; if (itemMatch.Match(left, right)) { return(null); } var childContext = new List <JToken>(); // Find common head while (commonHead < left.Count && commonHead < right.Count && itemMatch.Match(left[commonHead], right[commonHead])) { var index = commonHead; var child = Diff(left[index], right[index]); if (child != null) { result[$"{index}"] = child; } commonHead++; } // Find common tail while (commonTail + commonHead < left.Count && commonTail + commonHead < right.Count && itemMatch.Match(left[left.Count - 1 - commonTail], right[right.Count - 1 - commonTail])) { var index1 = left.Count - 1 - commonTail; var index2 = right.Count - 1 - commonTail; var child = Diff(left[index1], right[index2]); if (child != null) { result[$"{index2}"] = child; } commonTail++; } if (commonHead + commonTail == left.Count) { // Trivial case, a block (1 or more consecutive items) was added for (int index = commonHead; index < right.Count - commonTail; ++index) { result[$"{index}"] = new JArray(right[index]); } return(result); } if (commonHead + commonTail == right.Count) { // Trivial case, a block (1 or more consecutive items) was removed for (int index = commonHead; index < left.Count - commonTail; ++index) { if (result.ContainsKey(index.ToString())) { result.Remove(index.ToString()); } result[$"_{index}"] = new JArray(left[index], 0, (int)DiffOperation.Deleted); } return(result); } // Complex Diff, find the LCS (Longest Common Subsequence) List <JToken> trimmedLeft = left.ToList().GetRange(commonHead, left.Count - commonTail - commonHead); List <JToken> trimmedRight = right.ToList().GetRange(commonHead, right.Count - commonTail - commonHead); Lcs lcs = Lcs.Get(trimmedLeft, trimmedRight, itemMatch); for (int index = commonHead; index < left.Count - commonTail; ++index) { if (lcs.Indices1.IndexOf(index - commonHead) < 0) { // Removed if (result.ContainsKey(index.ToString())) { result.Remove(index.ToString()); } result[$"_{index}"] = new JArray(left[index], 0, (int)DiffOperation.Deleted); } } for (int index = commonHead; index < right.Count - commonTail; index++) { int indexRight = lcs.Indices2.IndexOf(index - commonHead); if (indexRight < 0) { // Added result[$"{index}"] = new JArray(right[index]); } else { int li = lcs.Indices1[indexRight] + commonHead; int ri = lcs.Indices2[indexRight] + commonHead; JToken diff = Diff(left[li], right[ri]); if (diff != null) { result[$"{index}"] = diff; } } } return(result); }
private JObject ArrayDiff(JArray left, JArray right) { var result = JObject.Parse(@"{ ""_t"": ""a"" }"); int commonHead = 0; int commonTail = 0; if (JToken.DeepEquals(left, right)) { return(null); } // Find common head while (commonHead < left.Count && commonHead < right.Count && JToken.DeepEquals(left[commonHead], right[commonHead])) { commonHead++; } // Find common tail while (commonTail + commonHead < left.Count && commonTail + commonHead < right.Count && JToken.DeepEquals(left[left.Count - 1 - commonTail], right[right.Count - 1 - commonTail])) { commonTail++; } if (commonHead + commonTail == left.Count) { // Trivial case, a block (1 or more consecutive items) was added for (int index = commonHead; index < right.Count - commonTail; ++index) { result[$"{index}"] = new JArray(right[index]); } return(result); } if (commonHead + commonTail == right.Count) { // Trivial case, a block (1 or more consecutive items) was removed for (int index = commonHead; index < left.Count - commonTail; ++index) { result[$"_{index}"] = new JArray(left[index], 0, (int)DiffOperation.Deleted); } return(result); } // Complex Diff, find the LCS (Longest Common Subsequence) List <JToken> trimmedLeft = left.ToList().GetRange(commonHead, left.Count - commonTail - commonHead); List <JToken> trimmedRight = right.ToList().GetRange(commonHead, right.Count - commonTail - commonHead); Lcs lcs = Lcs.Get(trimmedLeft, trimmedRight); for (int index = commonHead; index < left.Count - commonTail; ++index) { if (lcs.Indices1.IndexOf(index - commonHead) < 0) { // Removed result[$"_{index}"] = new JArray(left[index], 0, (int)DiffOperation.Deleted); } } for (int index = commonHead; index < right.Count - commonTail; index++) { int indexRight = lcs.Indices2.IndexOf(index - commonHead); if (indexRight < 0) { // Added result[$"{index}"] = new JArray(right[index]); } else { int li = lcs.Indices1[indexRight] + commonHead; int ri = lcs.Indices2[indexRight] + commonHead; JToken diff = Diff(left[li], right[ri]); if (diff != null) { result[$"{index}"] = diff; } } } return(result); }
private List <Microsoft.AspNetCore.JsonPatch.Operations.Operation> ArrayDiff(JArray left, JArray right) { var result = new List <Microsoft.AspNetCore.JsonPatch.Operations.Operation>(); int commonHead = 0; int commonTail = 0; if (JToken.DeepEquals(left, right)) { return(null); } // Find common head while (commonHead < left.Count && commonHead < right.Count && JToken.DeepEquals(left[commonHead], right[commonHead])) { commonHead++; } // Find common tail while (commonTail + commonHead < left.Count && commonTail + commonHead < right.Count && JToken.DeepEquals(left[left.Count - 1 - commonTail], right[right.Count - 1 - commonTail])) { commonTail++; } if (commonHead + commonTail == left.Count) { // Trivial case, a block (1 or more consecutive items) was added for (int index = commonHead; index < right.Count - commonTail; ++index) { result.Add(new Microsoft.AspNetCore.JsonPatch.Operations.Operation("add", right.Path, null, right[index])); //result[$"{index}"] = new JArray(right[index]); } return(result); } if (commonHead + commonTail == right.Count) { // Trivial case, a block (1 or more consecutive items) was removed for (int index = commonHead; index < left.Count - commonTail; ++index) { result.Add(new Microsoft.AspNetCore.JsonPatch.Operations.Operation("remove", $"{right.Path}/{index}", null, null)); //result[$"_{index}"] = new JArray(left[index], 0, (int)DiffOperation.Deleted); } return(result); } // Complex Diff, find the LCS (Longest Common Subsequence) List <JToken> trimmedLeft = left.ToList().GetRange(commonHead, left.Count - commonTail - commonHead); List <JToken> trimmedRight = right.ToList().GetRange(commonHead, right.Count - commonTail - commonHead); Lcs lcs = Lcs.Get(trimmedLeft, trimmedRight); for (int index = commonHead; index < left.Count - commonTail; ++index) { if (lcs.Indices1.IndexOf(index - commonHead) < 0) { // Removed result.Add(new Microsoft.AspNetCore.JsonPatch.Operations.Operation("remove", $"{right.Path}/{index}", null, null)); //result[$"_{index}"] = new JArray(left[index], 0, (int)DiffOperation.Deleted); } } for (int index = commonHead; index < right.Count - commonTail; index++) { int indexRight = lcs.Indices2.IndexOf(index - commonHead); if (indexRight < 0) { // Added result.Add(new Microsoft.AspNetCore.JsonPatch.Operations.Operation("add", right.Path, null, right[index])); //result[$"{index}"] = new JArray(right[index]); } else { int li = lcs.Indices1[indexRight] + commonHead; int ri = lcs.Indices2[indexRight] + commonHead; var diff = Diff(left[li], right[ri]); if (diff != null) { foreach (var operation in diff) { result.Add(operation); } //result[$"{index}"] = diff; } } } return(result); }