Skip to content

Commit

Permalink
introduced different result orders, prepared release 1.1.0 (#4)
Browse files Browse the repository at this point in the history
* introduced different result orders

* prepared release 1.1.0
  • Loading branch information
spkl authored Feb 3, 2021
1 parent 2a3e865 commit 2e07510
Show file tree
Hide file tree
Showing 7 changed files with 664 additions and 43 deletions.
52 changes: 35 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,14 @@ B: c b a b a c

To do this, we use the following code:
```csharp
// using spkl.Diffs;
string[] a = new[] { "a", "b", "c", "a", "b", "b", "a" };
string[] b = new[] { "c", "b", "a", "b", "a", "c" };
MyersDiff<string> diff = new MyersDiff<string>(a, b);
```
Using generic typing, you can diff all sorts of types. You can also customize which values are considered equal by specifying a third constructor parameter (IEqualityComparer&lt;T&gt;).

There are two methods to access the results: `GetResult()` and `GetEditScript()`.

### GetResult()
`GetResult()` returns the resulting diff as a sequence of tuples that represent lines. In this case, the return value would look like this:
| ResultType | AItem | BItem |
|------------|-------|-------|
| A | a | |
| B | | c |
| Both | b | b |
| A | c | |
| Both | a | a |
| Both | b | b |
| A | b | |
| Both | a | a |
| B | | c |

This is similar to how the result would be displayed in a visual comparison application. The AItem and BItem columns contain sequence A and B, respectively. The ResultType column shows whether a line contains a value from sequence A, B, or from both. You can see which values were matched with each other.
There are two methods to access the results: `GetEditScript()` and `GetResult()`.

### GetEditScript()
`GetEditScript()` returns a sequence of edit instructions. You can understand these as instructions to follow to transform sequence A to sequence B. Every instruction contains four integers, a starting line number in A and B and the number of lines to add or remove. In this case, the return value would look like this:
Expand Down Expand Up @@ -65,3 +50,36 @@ To better understand this, let's follow these instructions:
*(This adds the last "c")*

Following these instructions, `abcabba` is transformed to `cbabac`.


### GetResult()
`GetResult()` returns the resulting diff as a sequence of tuples that represent lines. In this case, the return value would look like this:
| ResultType | AItem | BItem |
|------------|-------|-------|
| A | a | |
| B | | c |
| Both | b | b |
| A | c | |
| Both | a | a |
| Both | b | b |
| A | b | |
| Both | a | a |
| B | | c |

This is similar to how the result would be displayed in a visual comparison application. The AItem and BItem columns contain sequence A and B, respectively. The ResultType column shows whether a line contains a value from sequence A, B, or from both. You can see which values were matched with each other.

### GetResult(ResultOrder)
You can specify the order in which you want unmatched lines to appear by using the `GetResult(ResultOrder)` overload. To visualize this, we need to use a new example.
```
A: a b c
B: x y
```

The following table shows how the result would be returned when specifying the different ResultOrder values AABB, BBAA, ABAB and BABA:
| AABB | BBAA | ABAB | BABA |
|:----:|:----:|:----:|:----:|
| a - | - x | a - | - x |
| b - | - y | - x | a - |
| c - | a - | b - | - y |
| - x | b - | - y | b - |
| - y | c - | c - | c - |
7 changes: 3 additions & 4 deletions src/Diffs.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
<Copyright>Copyright (c) 2021 Sebastian Fischer</Copyright>
<RepositoryUrl>https://github.com/spkl/Diffs</RepositoryUrl>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.1.0</FileVersion>
<Version>1.0.1</Version>
<FileVersion>1.1.0.0</FileVersion>
<Version>1.1.0</Version>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\keys\spkl.Diffs.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
Expand All @@ -22,8 +22,7 @@
This project uses Semantic Versioning (https://semver.org/).</Description>
<PackageTags>diff diffs difference algorithm ses shortest edit script myers</PackageTags>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<PackageReleaseNotes>- Added documentation comments to all public types and methods to explain usage.
- Fixed issue where the comparer passed into the MyersDiff&lt;T&gt; constructor was ignored.</PackageReleaseNotes>
<PackageReleaseNotes>- Introduced new GetResult overload to customize the preferred order of unmatched lines.</PackageReleaseNotes>
</PropertyGroup>

<ItemGroup>
Expand Down
68 changes: 62 additions & 6 deletions src/MyersDiff.cs → src/MyersDiff{T}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,43 @@ private bool AreEqual(int aIndex, int bIndex)
/// BItem: The item from sequence B, this is the default value/null if resultType is <see cref="ResultType.A"/>.
/// </summary>
/// <returns>An enumerable of diff lines containing one unmatched or two matched items.</returns>
/// <remarks>This is this equal to calling <see cref="GetResult(ResultOrder)"/> with <see cref="ResultOrder.AABB"/>.</remarks>
public IEnumerable<(ResultType ResultType, T AItem, T BItem)> GetResult()
{
return this.GetResult(ResultOrder.AABB);
}

/// <summary>
/// Gets the calculated diff result in the form of matched items/lines:
/// ResultType: Specifies whether the line includes only an item from A, from B or from both sequences.
/// AItem: The item from sequence A; this is the default value/null if resultType is <see cref="ResultType.B"/>.
/// BItem: The item from sequence B, this is the default value/null if resultType is <see cref="ResultType.A"/>.
/// </summary>
/// <param name="order">The order in which unmatched items/lines are returned.</param>
/// <returns>An enumerable of diff lines containing one unmatched or two matched items.</returns>
public IEnumerable<(ResultType ResultType, T AItem, T BItem)> GetResult(ResultOrder order)
{
ResultType GetPreferredNext(ResultType current)
{
if (current == ResultType.Both)
{
// A first or B first
return (order == ResultOrder.ABAB || order == ResultOrder.AABB) ? ResultType.A : ResultType.B;
}

if (order == ResultOrder.AABB || order == ResultOrder.BBAA)
{
// Section mode - keep same side.
return current;
}
else
{
// Line mode - switch side.
return current == ResultType.A ? ResultType.B : ResultType.A;
}
}

ResultType preferredNext = GetPreferredNext(ResultType.Both);
int currentA = 0, currentB = 0;
while (currentA < this.aRemoved.Length || currentB < this.bAdded.Length)
{
Expand All @@ -98,16 +133,37 @@ private bool AreEqual(int aIndex, int bIndex)
yield return (ResultType.Both, this.aValues[currentA], this.bValues[currentB]);
currentA++;
currentB++;
preferredNext = GetPreferredNext(ResultType.Both);
}
else if (this.aRemoved[currentA])
else if (preferredNext == ResultType.A)
{
yield return (ResultType.A, this.aValues[currentA], default(T));
currentA++;
if (this.aRemoved[currentA])
{
yield return (ResultType.A, this.aValues[currentA], default(T));
currentA++;
preferredNext = GetPreferredNext(ResultType.A);
}
else if (this.bAdded[currentB])
{
yield return (ResultType.B, default(T), this.bValues[currentB]);
currentB++;
preferredNext = GetPreferredNext(ResultType.B);
}
}
else if (this.bAdded[currentB])
else // preferredNext == ResultType.B
{
yield return (ResultType.B, default(T), this.bValues[currentB]);
currentB++;
if (this.bAdded[currentB])
{
yield return (ResultType.B, default(T), this.bValues[currentB]);
currentB++;
preferredNext = GetPreferredNext(ResultType.B);
}
else if (this.aRemoved[currentA])
{
yield return (ResultType.A, this.aValues[currentA], default(T));
currentA++;
preferredNext = GetPreferredNext(ResultType.A);
}
}
}
else if (currentA < this.aRemoved.Length)
Expand Down
25 changes: 25 additions & 0 deletions src/ResultOrder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace spkl.Diffs
{
/// <summary>
/// Determines in which order the <see cref="MyersDiff{T}.GetResult(ResultOrder)"/> method returns items.
/// </summary>
public enum ResultOrder
{
/// <summary>
/// Items are ordered in alternating sections, first A, then B.
/// </summary>
AABB,
/// <summary>
/// Items are ordered in alternating sections, first B, then A.
/// </summary>
BBAA,
/// <summary>
/// Items are ordered in alternating lines, first A, then B.
/// </summary>
ABAB,
/// <summary>
/// Items are ordered in alternating lines, first B, then A.
/// </summary>
BABA
}
}
10 changes: 8 additions & 2 deletions test/MyersDiffClass.ReferenceCase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ public string BString
}
}

public (ResultType ResultType, string AItem, string BItem)[] Result { get; set; }
public (ResultType ResultType, string AItem, string BItem)[] ResultAABB { get; set; }

public (ResultType ResultType, string AItem, string BItem)[] ResultBBAA { get; set; }

public (ResultType ResultType, string AItem, string BItem)[] ResultABAB { get; set; }

public (ResultType ResultType, string AItem, string BItem)[] ResultBABA { get; set; }

public (int LineA, int LineB, int CountA, int CountB)[] EditScript { get; set; }

Expand All @@ -34,4 +40,4 @@ public override string ToString()
}
}
}
}
}
Loading

0 comments on commit 2e07510

Please sign in to comment.