Skip to content

CollectionRandomizer as IEnumerable #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@
// ***********************************************************************

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using dotNetTips.Utility.Standard.Common;
@@ -26,12 +27,12 @@ namespace dotNetTips.Utility.Standard.Collections
/// <typeparam name="T">Generic type parameter.</typeparam>
/// <remarks>The CollectionRandomizer is designed to shuffle a collection and allow retrieving items by using GetNext().</remarks>
[Information(nameof(CollectionRandomizer<T>), author: "David McCarter and Kristine Tran", createdOn: "8/26/2020", modifiedOn: "8/27/2020", UnitTestCoverage = 100, BenchMarkStatus = BenchMarkStatus.None, Status = Status.Available)]
public sealed class CollectionRandomizer<T>
public sealed class CollectionRandomizer<T> : IEnumerator<T>, IEnumerable<T>
{
/// <summary>
/// The repeat.
/// </summary>
private readonly bool _repeat;
private int _repeat;

/// <summary>
/// The thread lock.
@@ -57,69 +58,83 @@ public sealed class CollectionRandomizer<T>
/// Initializes a new instance of the <see cref="CollectionRandomizer{T}" /> class.
/// </summary>
/// <param name="collection">The collection.</param>
/// <param name="repeat">If set to <c>true</c> and when using GetNext() the collection will repeat over and over and each time re-
/// <param name="repeat">set to <c>true</c> and when using GetNext() the collection will repeat over and over and each time re-
/// shuffled. Be careful of getting into an endless loop, it could cause your app to crash.</param>
/// <remarks>The collection cannot be changed after initialization.</remarks>
public CollectionRandomizer(IEnumerable<T> collection, bool repeat = false)
/// <exception cref="ArgumentInvalidException">Underlying collection is null.</exception>
public CollectionRandomizer(IEnumerable<T> collection, bool repeat) : this(collection, repeat ? -1 : 1)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="CollectionRandomizer{T}" /> class.
/// </summary>
/// <param name="collection">The collection.</param>
/// <param name="repeatCount">set to the number of times to repeat and when using MoveNext() the collection will repeat over and over and each time re-
/// shuffled. Defaults to 1. use -1 to repeat forever. Be careful of getting into an endless loop, it could cause your app to crash.</param>
/// <remarks>The collection cannot be changed after initialization.</remarks>
/// <exception cref="ArgumentInvalidException">Underlying collection is null.</exception>
public CollectionRandomizer(IEnumerable<T> collection, int repeatCount = 1)
{
this._collection = collection.ToImmutableArray();
this._repeat = repeat;
this._repeat = repeatCount;

// Validate Collection
if (this._collection.HasItems() == false)
{
throw new ArgumentInvalidException("Underlying collection is null.");
}
}


/// <summary>
/// Gets a value indicating whether this instance has remaining items.
/// </summary>
/// <value><c>true</c> if this instance has remaining items; otherwise, <c>false</c>. This value will be <c>false</c>
/// until the first time GetNext() is called and the shuffle is initalized.</value>
/// until the first time GetNext() is called and the shuffle is initialized.</value>
public bool HasRemainingItems { get; private set; }

/// <summary>
/// Gets the next item in the collection.
/// </summary>
/// <returns>T.</returns>
public T GetNext()
{
lock (this._threadLock)
{
this.Init();
/// <inheritdoc/>
public T Current => this._collectionEnumerator.Current;

var collectionItem = this._collectionEnumerator.Current;

this.HasRemainingItems = this._collectionEnumerator.MoveNext();
/// <inheritdoc/>
object? IEnumerator.Current => this.Current;

return collectionItem;
}
/// <inheritdoc/>
public void Dispose()
{
}

/// <summary>
/// Initializes this instance.
/// Gets the next item in the collection.
/// </summary>
/// <exception cref="NullReferenceException">Underlying collection is null.</exception>
private void Init()
/// <returns>T.</returns>
public bool MoveNext()
{
// Ignore if initialized unless repeat is true.
if (( this._initialized == true & this.HasRemainingItems ) ||
( this._initialized == true & this.HasRemainingItems == true & this._repeat == false ))
{
return;
}
this.HasRemainingItems = this._initialized && this._collectionEnumerator.MoveNext();
if (!this.HasRemainingItems && this._repeat !=0)
this.Reset();
return this.HasRemainingItems || this._repeat !=0;
}

// Validate Collection
if (this._collection.HasItems() == false)
/// <inheritdoc/>
public void Reset()
{
lock (this._threadLock)
{
throw new NullReferenceException("Underlying collection is null.");
}

// Shuffle Collection
this._collection = this._collection.Shuffle();

// Setup enumerator
this._collectionEnumerator = this._collection.GetEnumerator();
// Shuffle Collection
this._collection = this._collection.Shuffle();

// Move to first item
this.HasRemainingItems = this._collectionEnumerator.MoveNext();

this._initialized = true;
// Setup enumerator
this._collectionEnumerator = this._collection.GetEnumerator();
this._initialized = true;
--this._repeat;
this.HasRemainingItems = this._collectionEnumerator.MoveNext();
}
}

public IEnumerator<T> GetEnumerator() => this;
IEnumerator IEnumerable.GetEnumerator() => this;
}
}
Original file line number Diff line number Diff line change
@@ -2,7 +2,9 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using dotNetTips.Utility.Standard.Collections;
using dotNetTips.Utility.Standard.Common;
using dotNetTips.Utility.Standard.Tester;
using dotNetTips.Utility.Standard.Tester.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -23,17 +25,14 @@ public void GetNextRepeatTest()

var counter = 0;

do
while (collectionRandomizer.MoveNext() && counter < 55)
{
var item = collectionRandomizer.GetNext();
var item = collectionRandomizer.Current;
Debug.WriteLine(item.ToString());
counter++;
}

counter++;

Debug.WriteLine(item.ToString());

} while (counter < 55);

Assert.IsTrue(55 == counter);
Assert.AreEqual(55, counter);
}
[TestMethod]
public void GetNextTest()
@@ -44,27 +43,67 @@ public void GetNextTest()

var counter = 0;

do
while(collectionRandomizer.MoveNext())
{
var item = collectionRandomizer.GetNext();
var item = collectionRandomizer.Current;

counter++;
counter++;

Debug.WriteLine(item.ToString());

} while (collectionRandomizer.HasRemainingItems);
}

Assert.IsTrue(count == counter);
Assert.AreEqual(count,counter);
}

[TestMethod]
public void NullCollectionTest()
{
var collection = new List<PersonProper>();
var collectionRandomizer = new CollectionRandomizer<PersonProper>(collection);
Assert.ThrowsException<ArgumentInvalidException>(()=>new CollectionRandomizer<PersonProper>(collection));

}

[TestMethod]
public void RepeatCountTest()
{
const int count = 10;
const int repeatCnt = 3;
const int total = count * repeatCnt;
var collection = RandomData.GeneratePersonCollection<PersonProper>(count);
var collectionRandomizer = new CollectionRandomizer<PersonProper>(collection, repeatCnt);

var counter = 0;

Assert.ThrowsException<NullReferenceException>(collectionRandomizer.GetNext);
foreach(var item in collectionRandomizer)
{
Debug.WriteLine(item.Email);
counter++;
}

Assert.AreEqual(total,counter);
}
}

[TestMethod]
public void ShuffleTest()
{
const int count = 10;
const int repeatCnt = 2;

var collection = RandomData.GeneratePersonCollection<PersonProper>(count);
var collectionRandomizer = new CollectionRandomizer<PersonProper>(collection, repeatCnt);

var list1 = new List<PersonProper>(collectionRandomizer.Take(count));
var list2 = new List<PersonProper>(collectionRandomizer.Take(count));

Assert.IsFalse(list1.SequenceEqual(list2));

// Unshuffle to see if they started the same
list1.Sort();
list2.Sort();
Assert.IsTrue(list1.SequenceEqual(list2));
}


}
}