Skip to content

Commit

Permalink
IsReorderOf, Map->AddOrUpdate, Map->TryUpdate
Browse files Browse the repository at this point in the history
  • Loading branch information
ZacharyPatten committed Jan 17, 2021
1 parent f204e32 commit d2660e2
Show file tree
Hide file tree
Showing 7 changed files with 285 additions and 0 deletions.
19 changes: 19 additions & 0 deletions Examples/BasicsAndExtensions/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,25 @@ static void Main()
}
#endregion

#region IsReorderOf
{
Console.WriteLine(" Is IsReorderOf ----------------------");
Console.WriteLine();
Console.WriteLine(@" This is commonly called ""anagrams"".");
Console.WriteLine();

string abcdef = "abcdef";
string fedcba = "fedcba";
Console.WriteLine($@" IsReorderOf(""{abcdef}"", ""{fedcba}""): {IsReorderOf<char>(abcdef, fedcba)}");

string aabbcc = "aabbcc";
string abbbbc = "abbbbc";
Console.WriteLine($@" IsReorderOf(""{aabbcc}"", ""{abbbbc}""): {IsReorderOf<char>(aabbcc, abbbbc)}");

Console.WriteLine();
}
#endregion

#region Hamming Distance
{
Console.WriteLine(" HammingDistance----------------");
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,8 @@ IsPalindrome<...>(...);
IsInterleavedRecursive<...>(...);
IsInterleavedIterative<...>(...);
IsReorderOf<...>(...); // aka "anagrams"
// Note: supports System.Span<T> and any (non ref struct) int-indexed type
SortShuffle<T>(...);
SortBubble<T>(...);
Expand Down
114 changes: 114 additions & 0 deletions Sources/Towel/DataStructures/Map.cs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,120 @@ public bool TryAdd(K key, T value, out Exception? exception)
return true;
}

/// <summary>Adds or updates the value at the given key.</summary>
/// <param name="key">The key of the value to add or update.</param>
/// <param name="value">The value to add if not already present.</param>
/// <param name="update">The function to update the value if present.</param>
public void AddOrUpdate(K key, T value, Func<T, T> update)
{
if (update is null)
{
throw new ArgumentNullException(nameof(update));
}
AddOrUpdate<FuncRuntime<T, T>>(key, value, update);
}

/// <summary>Adds or updates the value at the given key.</summary>
/// <typeparam name="Update">The function to update the value if present.</typeparam>
/// <param name="key">The key of the value to add or update.</param>
/// <param name="value">The value to add if not already present.</param>
/// <param name="update">The function to update the value if present.</param>
public void AddOrUpdate<Update>(K key, T value, Update update = default)
where Update : struct, IFunc<T, T>
{
int location = GetLocation(key);
for (Node? node = _table[location]; node is not null; node = node.Next)
{
if (_equate.Do(node.Key, key))
{
node.Value = update.Do(node.Value);
return;
}
}
_table[location] = new Node(
value: value,
key: key,
next: _table[location]);
_count++;
if (_count > _table.Length * _maxLoadFactor)
{
float tableSizeFloat = (_count * 2) * (1 / _maxLoadFactor);
if (tableSizeFloat <= int.MaxValue)
{
int tableSize = (int)tableSizeFloat;
while (!IsPrime(tableSize))
{
tableSize++;
}
Resize(tableSize);
}
}
}

public bool TryUpdate(K key, T value)
{
int location = GetLocation(key);
for (Node? node = _table[location]; node is not null; node = node.Next)
{
if (_equate.Do(node.Key, key))
{
node.Value = value;
return true;
}
}
return false;
}

public bool TryUpdate(K key, Func<T, T> update)
{
if (update is null)
{
throw new ArgumentNullException(nameof(update));
}
return TryUpdate<FuncRuntime<T, T>>(key, update);
}

public bool TryUpdate<Update>(K key, Update update = default)
where Update : struct, IFunc<T, T>
{
int location = GetLocation(key);
for (Node? node = _table[location]; node is not null; node = node.Next)
{
if (_equate.Do(node.Key, key))
{
node.Value = update.Do(node.Value);
return true;
}
}
return false;
}

public bool TryUpdate(K key, out T? value, Func<T, T> update)
{
if (update is null)
{
throw new ArgumentNullException(nameof(update));
}
return TryUpdate<FuncRuntime<T, T>>(key, out value, update);
}

public bool TryUpdate<Update>(K key, out T? value, Update update = default)
where Update : struct, IFunc<T, T>
{
int location = GetLocation(key);
for (Node? node = _table[location]; node is not null; node = node.Next)
{
if (_equate.Do(node.Key, key))
{
node.Value = update.Do(node.Value);
value = node.Value;
return true;
}
}
value = default;
return false;
}

/// <summary>Tries to get a value by key.</summary>
/// <param name="key">The key of the value to get.</param>
/// <param name="value">The value if found or default.</param>
Expand Down
53 changes: 53 additions & 0 deletions Sources/Towel/Statics-SequenceAnalysis.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1296,5 +1296,58 @@ public static bool IsInterleavedIterative<T, Equate>(ReadOnlySpan<T> a, ReadOnly
}

#endregion

#region IsReorderOf

/// <summary>Checks if two spans are re-orders of each other meaning they contain the same number of each element.</summary>
/// <typeparam name="T">The element type of each span.</typeparam>
/// <param name="a">The first span.</param>
/// <param name="b">The second span.</param>
/// <param name="equate">The function for determining equality of elements.</param>
/// <param name="hash">The function for hashing the elements.</param>
/// <returns>True if both spans contain the same number of each element.</returns>
public static bool IsReorderOf<T>(ReadOnlySpan<T> a, ReadOnlySpan<T> b, Func<T, T, bool>? equate = null, Func<T, int>? hash = null) =>
IsReorderOf<T, FuncRuntime<T, T, bool>, FuncRuntime<T, int>>(a, b, equate ?? Equate, hash ?? DefaultHash);

/// <summary>Checks if two spans are re-orders of each other meaning they contain the same number of each element.</summary>
/// <typeparam name="T">The element type of each span.</typeparam>
/// <typeparam name="Equate">The function for determining equality of elements.</typeparam>
/// <typeparam name="Hash">The function for hashing the elements.</typeparam>
/// <param name="a">The first span.</param>
/// <param name="b">The second span.</param>
/// <param name="equate">The function for determining equality of elements.</param>
/// <param name="hash">The function for hashing the elements.</param>
/// <returns>True if both spans contain the same number of each element.</returns>
public static bool IsReorderOf<T, Equate, Hash>(ReadOnlySpan<T> a, ReadOnlySpan<T> b, Equate equate = default, Hash hash = default)
where Equate : struct, IFunc<T, T, bool>
where Hash : struct, IFunc<T, int>
{
if (a.IsEmpty && b.IsEmpty)
{
return true;
}
if (a.Length != b.Length)
{
return false;
}
MapHashLinked<int, T, Equate, Hash> counts = new(
equate: equate,
hash: hash,
expectedCount: a.Length);
foreach (T value in a)
{
counts.AddOrUpdate<IntIncrement>(value, 1);
}
foreach (T value in b)
{
if (!counts.TryUpdate<IntDecrement>(value, out int count) || count is -1)
{
return false;
}
}
return true;
}

#endregion
}
}
10 changes: 10 additions & 0 deletions Sources/Towel/Statics-Structs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,5 +94,15 @@ internal struct Func_int_int_T_JaggedArray_Get<T> : IFunc<int, int, T>
public static implicit operator Func_int_int_T_JaggedArray_Get<T>(T[][] jaggedArray) =>
new Func_int_int_T_JaggedArray_Get<T>() { JaggedArray = jaggedArray, };
}

internal struct IntIncrement : IFunc<int, int>
{
public int Do(int a) => a + 1;
}

internal struct IntDecrement : IFunc<int, int>
{
public int Do(int a) => a - 1;
}
}
}
33 changes: 33 additions & 0 deletions Sources/Towel/Towel.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2917,6 +2917,19 @@
<param name="exception">The exception that occured if the add failed.</param>
<returns>True if the value was added or false if not.</returns>
</member>
<member name="M:Towel.DataStructures.MapHashLinked`4.AddOrUpdate(`1,`0,System.Func{`0,`0})">
<summary>Adds or updates the value at the given key.</summary>
<param name="key">The key of the value to add or update.</param>
<param name="value">The value to add if not already present.</param>
<param name="update">The function to update the value if present.</param>
</member>
<member name="M:Towel.DataStructures.MapHashLinked`4.AddOrUpdate``1(`1,`0,``0)">
<summary>Adds or updates the value at the given key.</summary>
<typeparam name="Update">The function to update the value if present.</typeparam>
<param name="key">The key of the value to add or update.</param>
<param name="value">The value to add if not already present.</param>
<param name="update">The function to update the value if present.</param>
</member>
<member name="M:Towel.DataStructures.MapHashLinked`4.TryGet(`1,`0@,System.Exception@)">
<summary>Tries to get a value by key.</summary>
<param name="key">The key of the value to get.</param>
Expand Down Expand Up @@ -30756,6 +30769,26 @@
<member name="M:Towel.Statics.IsInterleavedIterative``2(System.ReadOnlySpan{``0},System.ReadOnlySpan{``0},System.ReadOnlySpan{``0},``1)">
<inheritdoc cref="M:Towel.Statics.IsInterleavedIterative_XML"/>
</member>
<member name="M:Towel.Statics.IsReorderOf``1(System.ReadOnlySpan{``0},System.ReadOnlySpan{``0},System.Func{``0,``0,System.Boolean},System.Func{``0,System.Int32})">
<summary>Checks if two spans are re-orders of each other meaning they contain the same number of each element.</summary>
<typeparam name="T">The element type of each span.</typeparam>
<param name="a">The first span.</param>
<param name="b">The second span.</param>
<param name="equate">The function for determining equality of elements.</param>
<param name="hash">The function for hashing the elements.</param>
<returns>True if both spans contain the same number of each element.</returns>
</member>
<member name="M:Towel.Statics.IsReorderOf``3(System.ReadOnlySpan{``0},System.ReadOnlySpan{``0},``1,``2)">
<summary>Checks if two spans are re-orders of each other meaning they contain the same number of each element.</summary>
<typeparam name="T">The element type of each span.</typeparam>
<typeparam name="Equate">The function for determining equality of elements.</typeparam>
<typeparam name="Hash">The function for hashing the elements.</typeparam>
<param name="a">The first span.</param>
<param name="b">The second span.</param>
<param name="equate">The function for determining equality of elements.</param>
<param name="hash">The function for hashing the elements.</param>
<returns>True if both spans contain the same number of each element.</returns>
</member>
<member name="M:Towel.Statics.Shuffle_XML">
<summary>
Sorts values into a randomized order.
Expand Down
54 changes: 54 additions & 0 deletions Tools/Towel_Testing/Statics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2082,5 +2082,59 @@ [TestMethod] public void IsInterleavedIterative_Testing()
}

#endregion

#region IsReorderOf

[TestMethod] public void IsReorderOf_Testing()
{
Assert.IsTrue(IsReorderOf<char>("a", "a"));
Assert.IsTrue(IsReorderOf<char>("ab", "ba"));
Assert.IsTrue(IsReorderOf<char>("abc", "cba"));

Assert.IsTrue(IsReorderOf<char>("aab", "baa"));
Assert.IsTrue(IsReorderOf<char>("aab", "aba"));
Assert.IsTrue(IsReorderOf<char>("aab", "aab"));

Assert.IsTrue(IsReorderOf<char>("aabb", "bbaa"));
Assert.IsTrue(IsReorderOf<char>("aabb", "abab"));
Assert.IsTrue(IsReorderOf<char>("aabb", "abba"));
Assert.IsTrue(IsReorderOf<char>("aabb", "aabb"));

Assert.IsFalse(IsReorderOf<char>("a", "b"));
Assert.IsFalse(IsReorderOf<char>("aa", "bb"));
Assert.IsFalse(IsReorderOf<char>("ab", "aa"));
Assert.IsFalse(IsReorderOf<char>("ab", "bb"));

Assert.IsFalse(IsReorderOf<char>("aa", "a"));
Assert.IsFalse(IsReorderOf<char>("a", "aa"));
Assert.IsFalse(IsReorderOf<char>("ab", "aab"));
Assert.IsFalse(IsReorderOf<char>("aab", "ab"));
Assert.IsFalse(IsReorderOf<char>("aabbcc", "aaabbcc"));
Assert.IsFalse(IsReorderOf<char>("aabbcc", "aabbbcc"));
Assert.IsFalse(IsReorderOf<char>("aabbcc", "aabbccc"));
Assert.IsFalse(IsReorderOf<char>("aaabbcc", "aabbcc"));
Assert.IsFalse(IsReorderOf<char>("aabbbcc", "aabbcc"));
Assert.IsFalse(IsReorderOf<char>("aabbccc", "aabbcc"));

Assert.IsFalse(IsReorderOf<char>("aabb", "aaab"));
Assert.IsFalse(IsReorderOf<char>("bbaa", "aaab"));

Assert.IsFalse(IsReorderOf<char>("aabbcc", "aaabcc"));
Assert.IsFalse(IsReorderOf<char>("aabbcc", "abbbcc"));
Assert.IsFalse(IsReorderOf<char>("aabbcc", "aabccc"));
Assert.IsFalse(IsReorderOf<char>("aabbcc", "abbccc"));

Assert.IsFalse(IsReorderOf<char>("a", ""));
Assert.IsFalse(IsReorderOf<char>("", "a"));
Assert.IsFalse(IsReorderOf<char>(null, "a"));
Assert.IsFalse(IsReorderOf<char>("a", null));

Assert.IsTrue(IsReorderOf<char>(null, null));
Assert.IsTrue(IsReorderOf<char>("", ""));
Assert.IsTrue(IsReorderOf<char>(null, ""));
Assert.IsTrue(IsReorderOf<char>("", null));
}

#endregion
}
}

0 comments on commit d2660e2

Please sign in to comment.