Reputation: 2412
I have a function that returns a read-only list of values. In some cases, this list of values can grow very large and can be described by an algorithm. I would like to have the list generate those values dynamically as requested rather than generate a list with all of them. Is there anything generic or a template or anything else that can get me started should I need to implement more than the algorithm myself?
I realize the idea itself is rather generic, but I tagged it for my specific case as a starting point.
Upvotes: 1
Views: 47
Reputation: 551
As dasblinkenlight mentions, List
has to hold the elements. As defined in the interfaces it implements, IList
and ICollection
. IEnumerable
is your only choice if you want to return something that represents your value list. Check this implementation.
public class FunctionBasedList<T> : IEnumerable<T>
{
public class Enumerator<T> : IEnumerator<T>
{
private int index;
private T current;
private FunctionBasedList<T> list;
internal Enumerator(FunctionBasedList<T> list)
{
this.list = list;
}
public T Current {
get
{
return current;
}
}
Object IEnumerator.Current
{
get
{
if (index == 0 || index == this.list.Count + 1)
{
throw new InvalidOperationException();
}
return current;
}
}
public bool MoveNext()
{
if (list.Count > index)
{
current = this.list[index];
index++;
return true;
}
return false;
}
public void Reset()
{
index = 0;
current = default(T);
}
public void Dispose()
{
}
}
public int Count
{
private set;
get;
}
public Func<int, T> Function
{
private set;
get;
}
public T this[int index]
{
get
{
if (index < 0 || index >= this.Count)
{
throw new IndexOutOfRangeException();
}
return this.Function(index);
}
}
public FunctionBasedList(int count, Func<int, T> function)
{
this.Count = count;
this.Function = function;
}
public Enumerator<T> GetEnumerator()
{
return new Enumerator<T>(this);
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return new Enumerator<T>(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new Enumerator<T>(this);
}
}
class Program
{
static void Main(string[] args)
{
FunctionBasedList<int> readOnlyList = new FunctionBasedList<int>(
10,
(index) =>
{
//Arbitrary function to generate a specific value for a specific index
return index * 100;
});
foreach (int r in readOnlyList)
{
Console.WriteLine(r);
}
//Loop through a subset of the list
for (int i = 5; i < 8; i++)
{
Console.WriteLine(readOnlyList[i]);
}
//Will throw an IndexOutOfRangeException
Console.WriteLine(readOnlyList[10]);
}
}
You can return IEnumerator
and use List<T>
or FunctionBasedList<T>
for different cases.
Upvotes: 0
Reputation: 726579
Since List<T>
represents an in-memory collection, there is no way to generate its members dynamically without storing them in memory.
However, you can do it with an IEnumerable<T>
: use a yield return
statement in a loop to generate the items of a sequence dynamically:
public IEnumerable<int> RandomlyIncreasing() {
var rnd = new Random();
var current = rnd.Next(0, 50);
for (int i = 0 ; i != 1000000 ; i++) {
yield return current;
current += rnd.Next(0, 10);
}
}
Upvotes: 2