Related
I try this:
public static int sum(List<int> list)
{
int sum = 0;
foreach (var item in list)
{
sum = item + sum;
}
return sum;
}
public static int sumAbsolute(List<int> list)
{
foreach (var item in list)
{
Math.Abs(item);
}
return sum(list);
}
and the in the main function:
static void Main(string[] args)
{
var list = new List<int>() {
-1,-2,-3
};
Console.WriteLine(sumAbsolute(list));
Console.ReadKey();
}
But the output is -6 and not 6.
So why doesn't my code work?
In short: because Math.Abs(item) returns an int that you dont use:
If you really want to replace all ints in the list, you could do:
for(int i = 0; i < list.Length; i++)
{
list[i] = Math.Abs(list[i]);
}
or with LINQ, this also doesn't need to modify the list:
public static int SumAbsolute(IEnumerable<int> list)
{
return list.Select(Math.Abs).Sum();
}
Let's say that we have two object types:
class Type1
{
public int Value {get;set;}
}
class Type2
{
public int Val {get; set;}
}
And we have two IEnumerable's for them:
IEnumerable<Type1> type1col;
IEnumerable<Type2> type2col;
What I want to have: each of type1col elements Value property value would have adequate type2col Val property value added.
We can say that both IEnumerables will have the same length always.
For now I am using this:
for (int i = 0; i < type1col.Count(); i++)
{
type1col.ElementAt(i).Value += type2col.ElementAt(i).Val;
}
but is there any better (faster & shorter) approach to do the same?
You can use IEnumerable.Zip:
var type1Col = type1Col.Select(x => x.Value)
.Zip(type2Col.Select(x => x.Value), (x, y) => x + y)
.Select(x => new Type1 { Value = x });
But as you allready have simple lists you can also use a classic loop and use indexers instead of IEnumerable.ElementAt:
for(int i = 0; i < type1Col.Count; i++)
{
type1Col[i].Value += typeo2Col[i];
}
Enumerating both together would be faster
[Benchmark]
public static void Enumerator()
{
using (var enumerator1 = Type1S.GetEnumerator())
{
using (var enumerator2 = Type2S.GetEnumerator())
{
while (enumerator1.MoveNext() && enumerator2.MoveNext())
{
enumerator1.Current.Value += enumerator2.Current.Val;
}
}
}
}
If you want to do an in-place modification of the elements of a sequence rather than having the overhead of creating a new sequence using Zip() you could do something like this:
public static void Combine<T1, T2>(IEnumerable<T1> target, IEnumerable<T2> modifyier, Action<T1, T2> modify)
{
using (var seq1 = target.GetEnumerator())
using (var seq2 = modifyier.GetEnumerator())
{
while (seq1.MoveNext() && seq2.MoveNext())
{
modify(seq1.Current, seq2.Current);
}
}
}
Which you would use like this:
IEnumerable<Type1> typecol1 = new List<Type1>{new Type1{Value = 1 }, new Type1 { Value = 2 } };
IEnumerable<Type2> typecol2 = new List<Type2>{new Type2{Val = 3}, new Type2{ Val = 4 } };
Combine(typecol1, typecol2, (type1, type2) => type1.Value += type2.Val);
foreach (var item in typecol1)
{
Console.WriteLine(item.Value);
}
I have following simplified program
using System;
using System.Collections.Generic;
using System.Text;
class ItemClass {
public int Id = 0;
public int[] Childs = new int[] { };
public int Count = 0;
}
class Class1 {
Dictionary<int, ItemClass> _Items = new Dictionary<int, ItemClass> { };
private void AddRecursive(int ItemID, int count, ref Dictionary<int, ItemClass> ItemList) {
if (!_Items.ContainsKey(ItemID)) {
return;
}
ItemClass _item = _Items[ItemID];
if (!ItemList.ContainsKey(ItemID)) {
ItemList.Add(ItemID, _item);
}
ItemList[ItemID].Count += count;
if (_item.Childs.Length > 0) {
foreach (int tmpItem in _item.Childs) {
AddRecursive(tmpItem, ItemList[ItemID].Count, ref ItemList);
}
}
}
public void Add(int item, int[] childs) {
if (!_Items.ContainsKey(item)) {
_Items.Add(item, new ItemClass() { Id = item, Childs = childs, Count = 0 });
}
}
public Dictionary<int, ItemClass> MakeList(int ItemID) {
if (!_Items.ContainsKey(ItemID)) {
return new Dictionary<int, ItemClass> { };
}
Dictionary<int, ItemClass> ItemList = new Dictionary<int, ItemClass> { };
AddRecursive(ItemID, 1, ref ItemList);
return ItemList;
}
}
class Program {
static void Main(string[] args) {
Class1 class1 = new Class1();
class1.Add(1111, new int[] { });
class1.Add(2222, new int[] { 1111 });
class1.Add(3333, new int[] { 1111, 2222 });
Dictionary<int, ItemClass> items1 = class1.MakeList(3333);
foreach (ItemClass item in items1.Values) {
Console.WriteLine(item.Id + " " + item.Count);
}
Console.WriteLine("");
Dictionary<int, ItemClass> items2 = class1.MakeList(3333);
foreach (ItemClass item in items2.Values) {
Console.WriteLine(item.Id + " " + item.Count);
}
Console.ReadKey();
}
}
It has a simple task of counting items and showing a list of items and their count. When I call the MakeList function the first time, results are expected.
Expected:
3333 1
1111 2
2222 1
3333 1
1111 2
2222 1
Actual
3333 1
1111 2
2222 1
3333 2
1111 7
2222 3
As I am re-declaring the variable ItemList, I'm expecting to see the same result when I call the function for second time, however it is like the results from previous call is cached and re-used.
Why this is happening and why is this behavior?
Is there any way to avoid it?
Actually there is nothing strange with it. You've just modified the value of Count property in your ItemClass object when you call AddRecursive method.
Assuming that you really want to get what you expected, you just need to deep clone your ItemClass object or simply create new instance and copy the original value of property.
ItemClass _item = new ItemClass() { Childs = _Items[ItemID].Childs, Count = _Items[ItemID].Count, Id = _Items[ItemID].Id };
Instead of this
Itemclass _item = _Items[ItemId]
You re-declaring ItemList, but using same objects from internal _Items : ItemClass _item = _Items[ItemID]; and incrementing count on same object. It is why part :). avoid part is to create new items maybe.
Your problem is that you alter the Count property of the ItemClass instances in the _Items dictionary while you run AddRecursive.
Get rid of that mutable Count property (it really shouldn't be in ItemClass), and simplify your code to
class ItemClass
{
public int Id = 0;
public int[] Childs = new int[] { };
}
class Class1
{
Dictionary<int, ItemClass> _Items = new Dictionary<int, ItemClass>();
private void AddRecursive(int itemId, Dictionary<int, int> itemList)
{
if (!_Items.ContainsKey(itemId))
return;
if (!itemList.ContainsKey(itemId))
itemList.Add(itemId, 1);
else
itemList[itemId] += 1;
var item = _Items[itemId];
if (item.Childs.Length > 0)
foreach (int tmpItem in item.Childs)
AddRecursive(tmpItem, itemList);
}
public void Add(int item, int[] childs)
{
if (!_Items.ContainsKey(item))
_Items.Add(item, new ItemClass() { Id = item, Childs = childs });
}
public Dictionary<int, int> MakeList(int itemId)
{
if (!_Items.ContainsKey(itemId))
return new Dictionary<int, int>();
var itemList = new Dictionary<int, int>();
AddRecursive(itemId, itemList);
return itemList;
}
}
Not sure if it's possible, but I'd like to be able to populate a List<T> based on what T is. Presently, I have something like this (please forgive the generic names - it's for testing purposes):
public static class CollectionsClass
{
List<Object1> list1 = new List<Object1>();
List<Object2> list2 = new List<Object2>();
List<Object3> list3 = new List<Object3>();
}
public static class ActionClass
{
public static void PopulateCollections()
{
Populate(CollectionsClass.list1, 0, 10);
Populate(CollectionsClass.list2, 20, 50);
Populate(CollectionsClass.list3, 30, 100);
}
private static void Populate(dynamic list, int minLimit, int maxLimit)
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
if (list.GetType() == typeof(List<Object1>))
{
list.Add(new Object1());
}
else if (list.GetType() == typeof(List<Object2>))
{
list.Add(new Object2());
}
else if (list.GetType() == typeof(List<Object3>))
{
list.Add(new Object3());
}
else
{
// put out an error
}
}
}
}
While that code works, I'd like to shrink it by doing something like:
list.Add(new list.ObjectType());
I've been messing around with reflections and getting types all day, but I just can't seem to figure this one out.
Don't use dynamics, use generics:
static void Populate<T>(List<T> list, ...) where T: new()
{
...
for (int i=0; i<rndNum; i++)
list.Add(new T());
}
Since you're already using dynamic, you should be able to add method to handle this:
private static void AddToList<T>(List<T> list) where T : new()
{
list.Add(new T());
}
Given that, you can write:
private static void Populate(dynamic list, int minLimit, int maxLimit)
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
AddToList(list);
}
}
Try to use generic method:
public static class CollectionsClass
{
public static List<Object1> list1 = new List<Object1>();
public static List<Object2> list2 = new List<Object2>();
public static List<Object3> list3 = new List<Object3>();
}
public static class ActionClass
{
public static void PopulateCollections()
{
Populate(CollectionsClass.list1, 0, 10);
Populate(CollectionsClass.list2, 20, 50);
Populate(CollectionsClass.list3, 30, 100);
}
private static void Populate<T>(List<T> list, int minLimit, int maxLimit)
where T : new()
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
list.Add(new T());
}
}
}
Sounds like you want a combination of generics and reflection.
First of all make it generic:
void Populate<T>(List<T> mylist)
Now you know the type of your list: it's T.
All that is left is looping and creating instances of a particular type T. For this you can use Activator.CreateInstance:
for(int i = 0; i < 5; i++){
mylist.Add((T) Activator.CreateInstance(typeof(T)));
}
With this sample code:
void Main()
{
Populate<Type1>(new List<Type1>());
Populate<Type2>(new List<Type2>());
}
void Populate<T>(List<T> mylist){
for(int i = 0; i < 5; i++){
mylist.Add((T) Activator.CreateInstance(typeof(T)));
}
foreach(var item in mylist){
Console.WriteLine (item);
}
}
class Type1 { }
class Type2 { }
class Type3 { }
You get this output:
This will rely on reflection to create an instance of your object any assumes there is a public non-parameter constructor available (otherwise an exception will be thrown from the Activator).
This is not quite desirable behaviour and I realized it as soon as I saw the other answers that use the where T : new() constraint in their generic function: use this method over mine.
I'll still leave it in here for completeness though (at the very least it demonstrates a possible trap).
Use factory to extract the creation logic, reflection to get the correct type, and Activator to get the instance.
public static class TFactory
{
public static T Getmplementation<T>()
{
var typeName = typeof(T).Name;
var type = Type.GetType(typeName);
if (type != null)
return Activator.CreateInstance(type) as T;
else
throw new NotImplementedException(typeName);
}
}
Then,
List.Add(TFactory.GetImplmentation<'T>());
You can use a generic with a new constraint to achieve this:
private static void PopulateList<T>(List<T> list, int minLimit, int maxLimit)
where T : new()
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
list.Add(new T());
}
}
The constraint is that the type T must provide a default constructor. If you want to add items to a List, you do not need the dynamic keyword as you can specify List<T> as parameter type directly.
If you cannot add a default constructor, you can also provide a creator function:
private static void PopulateList<T>(List<T> list, Func<int, T> creatorFunc,
int minLimit, int maxLimit)
{
var rnd = new Random();
int rndNum = rnd.Next(minLimit, maxLimit);
for (int i = 0; i < rndNum; i++)
{
list.Add(creatorFunc(i));
}
}
You call the method like this:
var lst = new List<MyObjectType>();
PopulateList<MyObjectType>(lst, x => new MyObjectType(x), 1, 7);
In this sample, the value of i is provided to the creatorFunc that returns a new object of type MyObjectType.
Read the edit below for more information.
I have some code below that I use to split a generic list of Object when the item is of a certain type.
public static IEnumerable<object>[] Split(this IEnumerable<object> tokens, TokenType type) {
List<List<object>> t = new List<List<object>>();
int currentT = 0;
t.Add(new List<object>());
foreach (object list in tokens) {
if ((list is Token) && (list as Token).TokenType == type) {
currentT++;
t.Add(new List<object>());
}
else if ((list is TokenType) && ((TokenType)list )== type) {
currentT++;
t.Add(new List<object>());
}
else {
t[currentT].Add(list);
}
}
return t.ToArray();
}
I dont have a clear question as much as I am curious if anyone knows of any ways I can optimize this code. I call it many times and it seems to be quite the beast as far as clock cycles go. Any ideas? I can also make it a Wiki if anyone is interested, maybe we can keep track of the latest changes.
Update: Im trying to parse out specific tokens. Its a list of some other class and Token classes. Token has a property (enum) of TokenType. I need to find all the Token classes and split on each of them.
{a b c T d e T f g h T i j k l T m}
would split like
{a b c}{d e}{f g h}{i j k l}{m}
EDIT UPDATE:
It seems like all of my speed problems come into the constant creation and addition of Generic Lists. Does anyone know how I can go about this without that?
This is the profile of what is happening if it helps anyone.
Your code looks fine.
My only suggestion would be replacing IEnumerable<object> with the non-generic IEnumerable. (In System.Collections)
EDIT:
On further inspection, you're casting more times than necessary.
Replace the if with the following code:
var token = list as Token;
if (token != null && token.TokenType == type) {
Also, you can get rid your currentT variable by writing t[t.Count - 1] or t.Last(). This will make the code clearer, but might have a tiny negative effect on performance.
Alternatively, you could store a reference to the inner list in a variable and use it directly. (This will slightly improve performance)
Finally, if you can change the return type to List<List<Object>>, you can return t directly; this will avoid an array copy and will be noticeably faster for large lists.
By the way, your variable names are confusing; you should swap the names of t and list.
Type-testing and casts can be a performance killer. If at all possible, your token types should implement a common interface or abstract class. Instead of passing in and object, you should pass in an IToken which wraps your object.
Here's some concept code you can use to get started:
using System;
using System.Collections.Generic;
namespace Juliet
{
interface IToken<T>
{
bool IsDelimeter { get; }
T Data { get; }
}
class DelimeterToken<T> : IToken<T>
{
public bool IsDelimeter { get { return true; } }
public T Data { get { throw new Exception("No data"); } }
}
class DataToken<T> : IToken<T>
{
public DataToken(T data)
{
this.Data = data;
}
public bool IsDelimeter { get { return false; } }
public T Data { get; private set; }
}
class TokenFactory<T>
{
public IToken<T> Make()
{
return new DelimeterToken<T>();
}
public IToken<T> Make(T data)
{
return new DataToken<T>(data);
}
}
class Program
{
static List<List<T>> SplitTokens<T>(IEnumerable<IToken<T>> tokens)
{
List<List<T>> res = new List<List<T>>();
foreach (IToken<T> token in tokens)
{
if (token.IsDelimeter)
{
res.Add(new List<T>());
}
else
{
if (res.Count == 0)
{
res.Add(new List<T>());
}
res[res.Count - 1].Add(token.Data);
}
}
return res;
}
static void Main(string[] args)
{
TokenFactory<string> factory = new TokenFactory<string>();
IToken<string>[] tokens = new IToken<string>[]
{
factory.Make("a"), factory.Make("b"), factory.Make("c"), factory.Make(),
factory.Make("d"), factory.Make("e"), factory.Make(),
factory.Make("f"), factory.Make("g"), factory.Make("h"), factory.Make(),
factory.Make("i"), factory.Make("j"), factory.Make("k"), factory.Make("l"), factory.Make(),
factory.Make("m")
};
List<List<string>> splitTokens = SplitTokens(tokens);
for (int i = 0; i < splitTokens.Count; i++)
{
Console.Write("{");
for (int j = 0; j < splitTokens[i].Count; j++)
{
Console.Write("{0}, ", splitTokens[i][j]);
}
Console.Write("}");
}
Console.ReadKey(true);
}
}
}
In principle, you can create instances of IToken<object> to have it generalized to tokens of multiple classes.
A: An all-lazy implementation will suffice if you just iterate through the results in a nested foreach:
using System;
using System.Collections.Generic;
public static class Splitter
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, Predicate<T> match)
{
using (IEnumerator<T> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
yield return Split(enumerator, match);
}
}
}
static IEnumerable<T> Split<T>(IEnumerator<T> enumerator, Predicate<T> match)
{
do
{
if (match(enumerator.Current))
{
yield break;
}
else
{
yield return enumerator.Current;
}
} while (enumerator.MoveNext());
}
}
Use it like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MyTokenizer
{
class Program
{
enum TokenTypes { SimpleToken, UberToken }
class Token { public TokenTypes TokenType = TokenTypes.SimpleToken; }
class MyUberToken : Token { public MyUberToken() { TokenType = TokenTypes.UberToken; } }
static void Main(string[] args)
{
List<object> objects = new List<object>(new object[] { "A", Guid.NewGuid(), "C", new MyUberToken(), "D", new MyUberToken(), "E", new MyUberToken() });
var splitOn = TokenTypes.UberToken;
foreach (var list in objects.Split(x => x is Token && ((Token)x).TokenType == splitOn))
{
foreach (var item in list)
{
Console.WriteLine(item);
}
Console.WriteLine("==============");
}
Console.ReadKey();
}
}
}
B: If you need to process the results some time later and you wish to do it out-of-order, or you partition on one thread and then possibly dispatch the segments to multiple threads, then this would probably provide a good starting point:
using System;
using System.Collections.Generic;
using System.Linq;
public static class Splitter2
{
public static IEnumerable<IEnumerable<T>> SplitToSegments<T>(this IEnumerable<T> source, Predicate<T> match)
{
T[] items = source.ToArray();
for (int startIndex = 0; startIndex < items.Length; startIndex++)
{
int endIndex = startIndex;
for (; endIndex < items.Length; endIndex++)
{
if (match(items[endIndex])) break;
}
yield return EnumerateArraySegment(items, startIndex, endIndex - 1);
startIndex = endIndex;
}
}
static IEnumerable<T> EnumerateArraySegment<T>(T[] array, int startIndex, int endIndex)
{
for (; startIndex <= endIndex; startIndex++)
{
yield return array[startIndex];
}
}
}
C: If you really must return a collection of List<T> -s - which I doubt, unless you explicitly want to mutate them some time later on -, then try to initialize them to a given capacity before copying:
public static List<List<T>> SplitToLists<T>(this IEnumerable<T> source, Predicate<T> match)
{
List<List<T>> lists = new List<List<T>>();
T[] items = source.ToArray();
for (int startIndex = 0; startIndex < items.Length; startIndex++)
{
int endIndex = startIndex;
for (; endIndex < items.Length; endIndex++)
{
if (match(items[endIndex])) break;
}
List<T> list = new List<T>(endIndex - startIndex);
list.AddRange(EnumerateArraySegment(items, startIndex, endIndex - 1));
lists.Add(list);
startIndex = endIndex;
}
return lists;
}
D: If this is still not enough, I suggest you roll your own lightweight List implementation that can copy a range directly to its internal array from another instance.
My first thought would be instead of looking up t[currentT] all the time, just store a currentList and add directly to that.
This is the best I could do to eliminate as much of the allocation times as possible for the function (should only allocate when it goes over the capacity, which should be no more than what is required to create the largest sub list in the results). I've tested this implementation and it works as you described.
Please note that the results of the prior sub list are destroyed when the next list in the group is accessed.
public static IEnumerable<IEnumerable> Split(this IEnumerable tokens, TokenType type)
{
ArrayList currentT = new ArrayList();
foreach (object list in tokens)
{
Token token = list as Token;
if ((token != null) && token.TokenType == type)
{
yield return currentT;
currentT.Clear();
//currentT = new ArrayList(); <-- Use this instead of 'currentT.Clear();' if you want the returned lists to be a different instance
}
else if ((list is TokenType) && ((TokenType)list) == type)
{
yield return currentT;
currentT.Clear();
//currentT = new ArrayList(); <-- Use this instead of 'currentT.Clear();' if you want the returned lists to be a different instance
}
else
{
currentT.Add(list);
}
}
}
EDIT
Here's another version that doesn't make use of another list at all (shouldn't be doing any allocations). Not sure how well this will compare, but it does work as requested (also I've got no idea how this one will go if you try to cache a sub 'array').
Also, both of these require a "using System.Collections" statement (in addition to the Generic namespace).
private static IEnumerable SplitInnerLoop(IEnumerator iter, TokenType type)
{
do
{
Token token = iter.Current as Token;
if ((token != null) && token.TokenType == type)
{
break;
}
else if ((iter.Current is TokenType) && ((TokenType)iter.Current) == type)
{
break;
}
else
{
yield return iter.Current;
}
} while (iter.MoveNext());
}
public static IEnumerable<IEnumerable> Split(this IEnumerable tokens, TokenType type)
{
IEnumerator iter = tokens.GetEnumerator();
while (iter.MoveNext())
{
yield return SplitInnerLoop(iter, type);
}
}
I think that there are broken cases for these scenarios where assuming that list items are lower case letters, and the item with matching token type is T:
{ T a b c ... };
{ ... x y z T };
{ ... j k l T T m n o ... };
{ T }; and
{ }
Which will result in:
{ { } { a b c ... } };
{ { ... x y z } { } };
{ { ... j k l } { } { } { m n o ... } };
{ { } }; and
{ }
Doing a straight refactoring:
public static IEnumerable<object>[] Split(this IEnumerable<object> tokens,
TokenType type) {
var outer = new List<List<object>>();
var inner = new List<object>();
foreach (var item in tokens) {
Token token = item as token;
if (token != null && token.TokenType == type) {
outer.Add(inner);
inner = new List<object>();
continue;
}
inner.Add(item);
}
outer.Add(inner);
return outer.ToArray();
}
To fix the broken cases (assuming that those are truly broken), I recommend:
public static IEnumerable<object>[] Split(this IEnumerable<object> tokens,
TokenType type) {
var outer = new List<List<object>>();
var inner = new List<object>();
var enumerator = tokens.GetEnumerator();
while (enumerator.MoveNext()) {
Token token = enumerator.Current as token;
if (token == null || token.TokenType != type) {
inner.Add(enumerator.Current);
}
else if (inner.Count > 0) {
outer.Add(inner);
inner = new List<object>();
}
}
return outer.ToArray();
}
Which will result in:
{ { a b c ... } };
{ { ... x y z } };
{ { ... j k l } { m n o ... } };
{ }; and
{ }
Using LINQ you could try this: (I did not test it...)
public static IEnumerable<object>[] Split(this IEnumerable<object> tokens, TokenType type)
{
List<List<object>> l = new List<List<object>>();
l.Add(new List<object>());
return tokens.Aggregate(l, (c, n) =>
{
var t = n as Token;
if (t != null && t.TokenType == type)
{
t.Add(new List<object>());
}
else
{
l.Last().Add(n);
}
return t;
}).ToArray();
}
Second try:
public static IEnumerable<object>[] Split(this IEnumerable<object> tokens, TokenType type)
{
var indexes = tokens.Select((t, index) => new { token = t, index = index }).OfType<Token>().Where(t => t.token.TokenType == type).Select(t => t.index);
int prevIndex = 0;
foreach (int item in indexes)
{
yield return tokens.Where((t, index) => (index > prevIndex && index < item));
prevIndex = item;
}
}
Here is one possibility
The Token class ( could be what ever class )
public class Token
{
public string Name { get; set; }
public TokenType TokenType { get; set; }
}
Now the Type enum ( this could be what ever other grouping factor )
public enum TokenType
{
Type1,
Type2,
Type3,
Type4,
Type5,
}
The Extention Method (Declare this anyway you choose)
public static class TokenExtension
{
public static IEnumerable<Token>[] Split(this IEnumerable<Token> tokens)
{
return tokens.GroupBy(token => ((Token)token).TokenType).ToArray();
}
}
Sample of use ( I used a web project to spin this )
List<Token> tokens = new List<Token>();
tokens.Add(new Token { Name = "a", TokenType = TokenType.Type1 });
tokens.Add(new Token { Name = "b", TokenType = TokenType.Type1 });
tokens.Add(new Token { Name = "c", TokenType = TokenType.Type1 });
tokens.Add(new Token { Name = "d", TokenType = TokenType.Type2 });
tokens.Add(new Token { Name = "e", TokenType = TokenType.Type2 });
tokens.Add(new Token { Name = "f", TokenType = TokenType.Type3 });
tokens.Add(new Token { Name = "g", TokenType = TokenType.Type3 });
tokens.Add(new Token { Name = "h", TokenType = TokenType.Type3 });
tokens.Add(new Token { Name = "i", TokenType = TokenType.Type4 });
tokens.Add(new Token { Name = "j", TokenType = TokenType.Type4 });
tokens.Add(new Token { Name = "k", TokenType = TokenType.Type4 });
tokens.Add(new Token { Name = "l", TokenType = TokenType.Type4 });
tokens.Add(new Token { Name = "m", TokenType = TokenType.Type5 });
StringBuilder stringed = new StringBuilder();
foreach (Token token in tokens)
{
stringed.Append(token.Name);
stringed.Append(", ");
}
Response.Write(stringed.ToString());
Response.Write("</br>");
var q = tokens.Split();
foreach (var list in tokens.Split())
{
stringed = new StringBuilder();
foreach (Token token in list)
{
stringed.Append(token.Name);
stringed.Append(", ");
}
Response.Write(stringed.ToString());
Response.Write("</br>");
}
So all I am soing is using Linq, feel free to add or remove, you can actualy go crazy on this and group on many diferent properties.
Do you need to convert it to an array? You could potentially use LINQ and delayed execution to return the results.
EDIT:
With the clarified question it would be hard to bend LINQ to make it return the results the way you want. If you still want to have the execution of each cycle delayed you could write your own enumerator.
I recommend perf testing this compared to the other options to see if there is a performance gain for your scenario if you attempt this approach. It might cause more overhead managing the iterator which would be bad for cases with little data.
I hope this helps.
// This is the easy way to make your own iterator using the C# syntax
// It will return sets of separated tokens in a lazy fashion
// This sample is based on the version provided by #Ants
public static IEnumerable<IEnumerable<object>> Split(this IEnumerable<object> tokens,
TokenType type) {
var current = new List<object>();
foreach (var item in tokens)
{
Token token = item as Token;
if (token != null && token.TokenType == type)
{
if( current.Count > 0)
{
yield return current;
current = new List<object>();
}
}
else
{
current.Add(item);
}
}
if( current.Count > 0)
yield return current;
}
Warning: This compiles but has still might have hidden bugs. It is getting late here.
// This is doing the same thing but doing it all by hand.
// You could use this method as well to lazily iterate through the 'current' list as well
// This is probably overkill and substantially more complex
public class TokenSplitter : IEnumerable<IEnumerable<object>>, IEnumerator<IEnumerable<object>>
{
IEnumerator<object> _enumerator;
IEnumerable<object> _tokens;
TokenType _target;
List<object> _current;
bool _isDone = false;
public TokenSplitter(IEnumerable<object> tokens, TokenType target)
{
_tokens = tokens;
_target = target;
Reset();
}
// Cruft from the IEnumerable and generic IEnumerator
public IEnumerator<IEnumerable<object>> GetEnumerator() { return this; }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerable<object> Current { get { return _current; } }
public void Dispose() { }
#region IEnumerator Members
object System.Collections.IEnumerator.Current { get { return Current; } }
// See if there is anything left to get
public bool MoveNext()
{
if (_isDone) return false;
FillCurrent();
return !_isDone;
}
// Reset the enumerators so that you could reuse this structure if you wanted
public void Reset()
{
_isDone = false;
_enumerator = _tokens.GetEnumerator();
_current = new List<object>();
FillCurrent();
}
// Fills the current set of token and then begins the next set
private void FillCurrent()
{
// Try to accumulate as many tokens as possible, this too could be an enumerator to delay the process more
bool hasNext = _enumerator.MoveNext();
for( ; hasNext; hasNext = _enumerator.MoveNext())
{
Token token = _enumerator.Current as Token;
if (token == null || token.TokenType != _target)
{
_current.Add(_enumerator.Current);
}
else
{
_current = new List<object>();
}
}
// Continue removing matching tokens and begin creating the next set
for( ; hasNext; hasNext = _enumerator.MoveNext())
{
Token token = _enumerator.Current as Token;
if (token == null || token.TokenType != _target)
{
_current.Add(_enumerator.Current);
break;
}
}
_isDone = !hasNext;
}
#endregion
}