Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit df7a63e

Browse files
authored
Merge pull request #3 from rvhuang/wip-enumerable-source
Support deferred execution
2 parents 3e1e8c4 + da1124a commit df7a63e

File tree

9 files changed

+549
-47
lines changed

9 files changed

+549
-47
lines changed

‎README.md‎

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
**KMP Algorithm .NET** is the .NET implementation of Knuth–Morris–Pratt algorithm. The project defines a set of extension methods that apply the algorithm to strings and lists.
66

7-
Unlike traditional KMP algorithm uses which are focused on string searching, the project provides a generic programming model of using KMP algorithm on [IList(T)](https://docs.microsoft.com/en-us/dotnet/core/api/system.collections.generic.ilist-1) and [IReadOnlyList(T)](https://docs.microsoft.com/en-us/dotnet/core/api/system.collections.generic.ireadonlylist-1), as long as type T is [equatable](https://docs.microsoft.com/en-us/dotnet/core/api/system.iequatable-1). This expands the applicability of the algorithm, making searching an array of bytes in a longer array, or a collection of floats in an array of floats with same algorithm possible. In some cases, you may specify optional parameter [IEqualityComparer(T)](https://docs.microsoft.com/en-us/dotnet/core/api/system.collections.generic.iequalitycomparer-1) instance to provide different comparison behavior for type T.
7+
Unlike traditional KMP algorithm uses which are focused on string instances, the project provides a set of generic APIs that apply KMP algorithm to [IEnumerable(T)](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1), [IList(T)](https://docs.microsoft.com/en-us/dotnet/core/api/system.collections.generic.ilist-1) and [IReadOnlyList(T)](https://docs.microsoft.com/en-us/dotnet/core/api/system.collections.generic.ireadonlylist-1), as long as type T is [equatable](https://docs.microsoft.com/en-us/dotnet/core/api/system.iequatable-1). This expands the applicability of the algorithm, making searching an array of bytes in a longer array, or a collection of floats in an array of floats with same algorithm possible. In some cases, you may specify optional parameter [IEqualityComparer(T)](https://docs.microsoft.com/en-us/dotnet/core/api/system.collections.generic.iequalitycomparer-1) instance to provide different comparison behavior for type `T`.
88

99
The project also includes a "backward" version of KMP algorithm that searches the last occurrence of the target within the instance.
1010

@@ -67,13 +67,44 @@ The project provides iterator pattern for forward and backward index enumeration
6767

6868
In this example, caller can start enumerating each index before all indexes are found.
6969

70+
### Searching in Deferred Execution
71+
72+
The project provides a set of `IndexOf` APIs optimized for [IEnumerable(T)](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1) instance that is produced in **deferred execution**. That is, the search can start before whole collection is ready. The APIs are defined in `AlgorithmForce.Searching.Deferred` namespace.
73+
74+
The following example shows how to search an array of numbers in `Enumerable.Range()`.
75+
76+
```cs
77+
// using AlgorithmForce.Searching.Deferred
78+
79+
var s = Enumerable.Range(0, 100); // deferred execution
80+
var t = new[] { 95, 96, 97, 98, 99 };
81+
82+
Console.WriteLine(s.IndexOf(t)); // 95
83+
```
84+
85+
A set of APIs that wrap [TextReader](https://docs.microsoft.com/en-us/dotnet/api/system.io.textreader) and [BinaryReader](https://docs.microsoft.com/en-us/dotnet/api/system.io.binaryreader) as `IEnumerable(T)` instances can be used together in order to search the collection in streamed content. The following code snippet shows how to search an array in `StringReader` by applying `AsCharEnumerable()` API.
86+
87+
```cs
88+
var s = "Vrogros, the Underlord, is a melee strength hero.";
89+
var t = new[] { 'U', 'n', 'd', 'e', 'r', 'l', 'o', 'r', 'd' };
90+
91+
using (var reader = new StringReader(s))
92+
{
93+
Console.WriteLine(reader.AsCharEnumerable().IndexOf(t));
94+
// 13
95+
}
96+
```
97+
7098
## Future Works
7199

72-
* Source collection with deferred execution
100+
* `IndexOfAny()` and `IndexesOfAll()` implementation
73101
* Vertical Search in a collecton of collections
74-
* `IndexOfAny` implementation
75102

76103
## Platform
77104

78-
This project currently targets .NET Core only.
105+
This project targets [.NET Standard 1.6](https://github.com/dotnet/standard/blob/master/docs/versions/netstandard1.6.md) currently.
106+
107+
## License
108+
109+
The project is licesed under the [MIT license](LICENSE). Feel free to use and modify the code in your algorithm homeworks.
79110

‎src/AlgorithmForce.Searching.Test/AlgorithmForce.Searching.Test.csproj‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@
1111
</PropertyGroup>
1212

1313
<ItemGroup>
14-
<Compile Include="..\AlgorithmForce.Searching\Extensions.cs;..\AlgorithmForce.Searching\ListWrapper.cs;..\AlgorithmForce.Searching\StringWrapper.cs" />
14+
<Compile Include="..\AlgorithmForce.Searching\Extensions.cs;" />
15+
<Compile Include="..\AlgorithmForce.Searching\ListWrapper.cs;" />
16+
<Compile Include="..\AlgorithmForce.Searching\StringWrapper.cs;" />
17+
<Compile Include="..\AlgorithmForce.Searching\TableBuilder.cs;" />
18+
<Compile Include="..\AlgorithmForce.Searching\Deferred\EnumerableExtensions.cs;" />
19+
<Compile Include="..\AlgorithmForce.Searching\Deferred\ReaderExtensions.cs;" />
1520
</ItemGroup>
1621

1722
<ItemGroup>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
using System.IO;
2+
using System.Linq;
3+
using Xunit;
4+
using Xunit.Abstractions;
5+
6+
namespace AlgorithmForce.Searching.Test
7+
{
8+
using Deferred;
9+
10+
public class EnumerableExtensionsTest
11+
{
12+
private readonly ITestOutputHelper _output;
13+
14+
public EnumerableExtensionsTest(ITestOutputHelper output)
15+
{
16+
_output = output;
17+
}
18+
19+
[Fact]
20+
public void TestCaseEnumerableIndexOf()
21+
{
22+
var s = Enumerable.Range(0, 100);
23+
var t = new[] { 95, 96, 97, 98, 99 };
24+
25+
Assert.Equal(95, EnumerableExtensions.IndexOf(s, t, 0, null));
26+
}
27+
28+
[Fact]
29+
public void TestCaseEnumerableIndexOfNotFound()
30+
{
31+
var s = Enumerable.Range(0, 100);
32+
var t = new[] { 90, 92, 94, 96, 98 };
33+
34+
Assert.Equal(-1, EnumerableExtensions.IndexOf(s, t, 0, null));
35+
}
36+
37+
[Fact]
38+
public void TestCaseEnumerableIndexOfWithTextReader()
39+
{
40+
var s = string.Concat("Vrogros, the Underlord, is a melee strength hero ",
41+
"whose commanding presence is crucial to his team's success. ",
42+
"With his long-lasting abilities, Underlord is able to ",
43+
"control wide areas of the battlefield during teamfights.");
44+
var t = new[] { 'U', 'n', 'd', 'e', 'r', 'l', 'o', 'r', 'd' };
45+
46+
using (var reader = new StringReader(s))
47+
{
48+
Assert.Equal(s.IndexOf(string.Concat(t)), EnumerableExtensions.IndexOf(reader.AsCharEnumerable(), t, 0, null));
49+
}
50+
}
51+
52+
[Fact]
53+
public void TestCaseEnumerableIndexOfWithTextReaderNotFound()
54+
{
55+
var s = string.Concat("Vrogros, the Underlord, is a melee strength hero ",
56+
"whose commanding presence is crucial to his team's success. ",
57+
"With his long-lasting abilities, Underlord is able to ",
58+
"control wide areas of the battlefield during teamfights.");
59+
var t = new[] { 'S', 'u', 'n', ' ', 'W', 'u', 'k', 'o', 'n', 'g' };
60+
61+
using (var reader = new StringReader(s))
62+
{
63+
Assert.Equal(s.IndexOf(string.Concat(t)), EnumerableExtensions.IndexOf(reader.AsCharEnumerable(), t, 0, null));
64+
}
65+
}
66+
67+
[Fact]
68+
public void TestCaseEnumerableIndexOfWithStartIndex()
69+
{
70+
var s = Enumerable.Range(0, 100);
71+
var t = new[] { 95, 96, 97, 98, 99 };
72+
73+
Assert.Equal(95, EnumerableExtensions.IndexOf(s, t, 20, null));
74+
}
75+
76+
[Fact]
77+
public void TestCaseEnumerableIndexOfWithStartIndexNotFound()
78+
{
79+
var s = Enumerable.Range(0, 100);
80+
var t = new[] { 95, 96, 97, 98, 99 };
81+
82+
Assert.Equal(-1, EnumerableExtensions.IndexOf(s, t, 97, null));
83+
}
84+
85+
[Fact]
86+
public void TestCaseEnumerableIndexOfWithTextReaderAndStartIndex()
87+
{
88+
var s = string.Concat("Vrogros, the Underlord, is a melee strength hero ",
89+
"whose commanding presence is crucial to his team's success. ",
90+
"With his long-lasting abilities, Underlord is able to ",
91+
"control wide areas of the battlefield during teamfights.");
92+
var t = new[] { 'U', 'n', 'd', 'e', 'r', 'l', 'o', 'r', 'd' };
93+
94+
using (var reader = new StringReader(s))
95+
{
96+
Assert.Equal(s.IndexOf(string.Concat(t), 160), EnumerableExtensions.IndexOf(reader.AsCharEnumerable(), t, 160, null));
97+
}
98+
}
99+
100+
[Fact]
101+
public void SkipTest()
102+
{
103+
var s = Enumerable.Range(5, 100);
104+
105+
using (var enumerator = s.GetEnumerator())
106+
{
107+
EnumerableExtensions.Skip(enumerator, 55).MoveNext();
108+
Assert.Equal(s.Skip(55).First(), enumerator.Current);
109+
}
110+
}
111+
}
112+
}

‎src/AlgorithmForce.Searching.Test/TableBuildingTest.cs‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public void TestCase1()
1818
{
1919
var input = "abcabx";
2020
var expected = new[] { -1, 0, 0, 0, 1, 2 };
21-
var actual = Extensions.BuildTable(input.AsReadOnlyList(), EqualityComparer<char>.Default);
21+
var actual = TableBuilder.BuildTable(input.AsReadOnlyList(), EqualityComparer<char>.Default);
2222

2323
_output.WriteLine("Expected:\t{0}", string.Join(", ", expected));
2424
_output.WriteLine("Actual:\t{0}", string.Join(", ", actual));
@@ -31,7 +31,7 @@ public void TestCase2()
3131
{
3232
var input = "abcdex";
3333
var expected = new[] { -1, 0, 0, 0, 0, 0 };
34-
var actual = Extensions.BuildTable(input.AsReadOnlyList(), EqualityComparer<char>.Default);
34+
var actual = TableBuilder.BuildTable(input.AsReadOnlyList(), EqualityComparer<char>.Default);
3535

3636
_output.WriteLine("Expected:\t{0}", string.Join(", ", expected));
3737
_output.WriteLine("Actual:\t{0}", string.Join(", ", actual));
@@ -44,7 +44,7 @@ public void TestCase3()
4444
{
4545
var input = "ababaaaba";
4646
var expected = new[] { -1, 0, 0, 1, 2, 3, 1, 1, 2 };
47-
var actual = Extensions.BuildTable(input.AsReadOnlyList(), EqualityComparer<char>.Default);
47+
var actual = TableBuilder.BuildTable(input.AsReadOnlyList(), EqualityComparer<char>.Default);
4848

4949
_output.WriteLine("Expected:\t{0}", string.Join(", ", expected));
5050
_output.WriteLine("Actual:\t{0}", string.Join(", ", actual));
@@ -57,7 +57,7 @@ public void TestCase4()
5757
{
5858
var input = "aaaaaaaab";
5959
var expected = new[] { -1, 0, 1, 2, 3, 4, 5, 6, 7 };
60-
var actual = Extensions.BuildTable(input.AsReadOnlyList(), EqualityComparer<char>.Default);
60+
var actual = TableBuilder.BuildTable(input.AsReadOnlyList(), EqualityComparer<char>.Default);
6161

6262
_output.WriteLine("Expected:\t{0}", string.Join(", ", expected));
6363
_output.WriteLine("Actual:\t{0}", string.Join(", ", actual));

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /