I just moved the blog to new address: http://marcinjuraszek.com
You should be redirected to new page in few seconds. If you don't want to wait just click link above.
by Marcin Juraszek
public IEnumerable<IEnumerable<T>> Partition<T>(IEnumerable<T> source, int size)
{
if (source == null)
throw new ArgumentNullException("list");
if (size < 1)
throw new ArgumentOutOfRangeException("size");
int index = 1;
IEnumerable<T> partition = source.Take(size).AsEnumerable();
while (partition.Any())
{
yield return partition;
partition = source.Skip(index++ * size).Take(size).AsEnumerable();
}
}
Question is, it the algorithm good and efficient? It returns correct results, that's for sure. But that's not the only important part of every algorithm. Unfortunately, I must say that the algorithm is no good. To answer why it's no a good algorithm? I'd like to show you another approach on solving the same problem:public IEnumerable<IEnumerable<T>> Partition<T>(IEnumerable<T> source, int size)
{
var partition = new List<T>(size);
var counter = 0;
using (var enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
partition.Add(enumerator.Current);
counter++;
if (counter % size == 0)
{
yield return partition.ToList();
partition.Clear();
counter = 0;
}
}
if (counter != 0)
yield return partition;
}
}
Is has exactly the same signature and returns exactly the same results. Why is it better then? There are couple possible answers:var enumSource = Enumerable.Range(0, size);
var arraySource = enumSource.ToArray();
var listSource = arraySource.ToList();
You may wonder why I tried the same algorithm on three different collections. That's because of how Skip/Take solution works: it iterates from that beginning of collection every time new partition is requested. It may not be important if your source is static collection (like Array or List), but it will cause Enumerable.Range to generate the collection every time again and again. That's really not necessary, is it?public bool Exists(Predicate<T> match)
public T Find(Predicate<T> match)
public List<T> FindAll(Predicate<T> match)
public int FindIndex(Predicate<T> match)
public int FindIndex(int startIndex, Predicate<T> match)
public int FindIndex(int startIndex, int count, Predicate<T> match)
public T FindLast(Predicate<T> match)
public int FindLastIndex(Predicate<T> match)
public int FindLastIndex(int startIndex, Predicate<T> match)
public int FindLastIndex(int startIndex, int count, Predicate<T> match)
public int IndexOf(T item)
public int IndexOf(T item, int index)
public int IndexOf(T item, int index, int count)
public int LastIndexOf(T item)
public int LastIndexOf(T item, int index)
public int LastIndexOf(T item, int index, int count)
public T Find(Predicate<T> match)
public List<T> FindAll(Predicate<T> match)
public int FindIndex(int startIndex, int count, Predicate<T> match)
public T FindLast(Predicate<T> match)
public int FindLastIndex(int startIndex, int count, Predicate<T> match)
public T Find(Predicate<T> match)
{
// parameter check skipped
for (int i = 0; i < this._size; i++)
{
if (match(this._items[i]))
{
return this._items[i];
}
}
return default(T);
}
public int FindIndex(int startIndex, int count, Predicate<T> match)
{
// parameter checks skipped
int num = startIndex + count;
for (int i = startIndex; i < num; i++)
{
if (match(this._items[i]))
{
return i;
}
}
return -1;
}