I've got a Type that we'll call Foo that can hold a collection of children Foo objects. Foo is Disposable, so when ever a child is disposed of, it will then add itself to the parent's Children collection.
An example usage of this looks like:
using (var a = AddChild(Root, "a"))
{
using (var a1 = AddChild(a, "a1"))
{
using (var a1a = AddChild(a1, "a1a"))
{
}
}
In this example a1a is only added to a1 when it is disposed, and not before. What I am having difficulty in figuring out is a clean way of writing a GetAllFoos method that returns all of the objects in a flattened list, in a FILO order.
In this case, would I just recursively iterate over each child, or is there some fancy LINQ I can use to try and consolidate these collections? I'm using this to take performance measurement snapshots through-out the app, and it's possible that we would call GetAllMeasurements in some cases during a profile so the performance of the method call is important.
This is a complete example app that shows what the expected results would look like. I have to support both FIFO and FILO. I've got a FIFO implementation working but I'm not sure on the best way to handle this inversely for FILO.
using System;
using System.Collections.Generic;
using System.Linq;
namespace FILO_Example
{
public class Foo : IDisposable
{
internal Foo parent;
public Foo(Foo parent = null)
{
this.parent = parent;
}
public string Name { get; set; }
public List<Foo> Children { get; } = new List<Foo>();
public void Dispose() => this.parent.Children.Add(this);
}
class Program
{
public static Foo Root { get; } = new Foo { Name = "Root" };
static void Main(string[] args)
{
// level 1
using (var a = AddChild(Root, "a"))
{
using (var a1 = AddChild(a, "a1"))
{
using (var a1a = AddChild(a1, "a1a"))
{
}
}
using (var a2 = AddChild(a, "a2"))
{
}
}
using (var b = AddChild(Root, "b"))
{
using (var b1 = AddChild(b, "b1"))
{
}
}
List<Foo> allFoos = GetAllFoosFILO().ToList();
Console.WriteLine(allFoos[0]); // Should be b1
Console.WriteLine(allFoos[1]); // Should be b
Console.WriteLine(allFoos[2]); // Should be a2
Console.WriteLine(allFoos[3]); // Should be a1a
Console.WriteLine(allFoos[4]); // Should be a1
Console.WriteLine(allFoos[5]); // Should be a
}
static IEnumerable<Foo> GetAllFoosFILO()
{
return new List<Foo>();
}
static IEnumerable<Foo> GetAllFoosFIFO()
{
var fooStack = new Stack<Foo>();
fooStack.Push(Root);
while (fooStack.Count > 0)
{
Foo currentFoo = fooStack.Pop();
yield return currentFoo;
// If we have children, add them in reverse order so that it's a First-In-First-Out stack
// then the while loop will yield each child element.
if (currentFoo.Children.Count > 0)
{
List<Foo> fooChildren = currentFoo.Children;
for (int currentIndex = fooChildren.Count - 1; currentIndex >= 0; currentIndex--)
{
fooStack.Push(fooChildren[currentIndex]);
}
}
}
}
static Foo AddChild(Foo parent, string name)
{
var child = new Foo(parent) { Name = name };
return child;
}
}
}
As I mentioned in the comments, you have a tree structure. There is no fancy efficient standard LINQ solution, but you can utilize the quite efficient generic Traverse method form my answer to Enumerating Directories iteratively in "postorder":
public static class TreeHelper
{
public static IEnumerable<T> Traverse<T>(T node, Func<T, IEnumerable<T>> childrenSelector, bool preOrder = true)
{
var stack = new Stack<IEnumerator<T>>();
var e = Enumerable.Repeat(node, 1).GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
var item = e.Current;
var children = childrenSelector(item);
if (children == null)
yield return item;
else
{
if (preOrder) yield return item;
stack.Push(e);
e = children.GetEnumerator();
}
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
if (!preOrder) yield return e.Current;
}
}
finally
{
e.Dispose();
while (stack.Count != 0) stack.Pop().Dispose();
}
}
}
With that helper, the GetAllFoosFIFO() is simple as that:
static IEnumerable<Foo> GetAllFoosFIFO()
{
return TreeHelper.Traverse(Root, foo => foo.Children.Count > 0 ? foo.Children : null);
}
while for GetAllFoosFILO() you need to pass preorder = false and iterate Children in reverse order:
static IEnumerable<Foo> GetAllFoosFILO()
{
return TreeHelper.Traverse(Root, foo => foo.Children.Count > 0 ?
Enumerable.Range(0, foo.Children.Count)
.Select(i => foo.Children[foo.Children.Count - 1 - i]) : null, false);
}
This should work:
private static IEnumerable<Foo> GetAllFoosFILO(Foo foo)
{
foreach (var c in ((IEnumerable<Foo>)foo.Children).Reverse())
{
var cc = GetAllFoosFILO(c);
foreach (var ccc in cc)
{
yield return ccc;
}
yield return c;
}
}
The weird cast in first foreach loop is for preventing use of List<T>.Reverse instead of Enumerable.Reverse<TSource> extension method which helps us to traverse tree in so called FILO way.
Bonus
With some small touches you can write FIFO like:
private static IEnumerable<Foo> GetAllFoosFIFO(Foo foo)
{
foreach (var c in foo.Children)
{
yield return c;
var cc = GetAllFoosFIFO(c);
foreach (var ccc in cc)
{
yield return ccc;
}
}
}
Related
Period|1|
AA|0|0|32.39|0|0|-0.12|
BB|0|-1794.62|
CC|Entity1|25|31.48|244.1|
DD|Entity2|25|0|0|
Period|2|
AA|0|0|32.39|0|0|-0.12|
BB|0|-1794.62|
CC|Entity1|25|31.48|244.1|
EE|Entity2|25|0|0|
FF|Entity3|25|0|0|
GG|Entity4|25|0|0|
HH|Entity5|25|0|0|
Period|3|
AA|0|0|32.39|0|0|-0.12|
BB|0|-1794.62|
Consider the above collection as:
IEnumerable<IEnumerable<string>> data;
First Enumerable is each line.
Second Enumerable is each line separated by delimiter |
I would like to group this by each period:
Expected result:
Period1 (Group Key)
AA|0|0|32.39|0|0|-0.12|
BB|0|-1794.62|
CC|Entity1|25|31.48|244.1|
DD|Entity2|25|0|0|
Period2 (Group Key)
AA|0|0|32.39|0|0|-0.12|
BB|0|-1794.62|
CC|Entity1|25|31.48|244.1|
EE|Entity2|25|0|0|
FF|Entity3|25|0|0|
GG|Entity4|25|0|0|
HH|Entity5|25|0|0|
Period3 (Group Key)
AA|0|0|32.39|0|0|-0.12|
BB|0|-1794.62|
Current implementation:
foreach (var dataPerPeriod in data.Take(5))
{
yield return new DataPerPeriod(dataPerPeriod);
}
but as you can see only the first period has 5 elements including the would-be key element (period).
Therefore I do not understand how to approach this problem.
I have made help class for your DataPerPeriod:
public class DataPerPeriod
{
public string Name { get; set; }
public List<IEnumerable<string>> Lines { get; set;}
}
Than i could aggregate it with this query:
var res = data.Aggregate(new List<DataPerPeriod>(), (a, b) =>
{
if (b.First() =="Period")
{
a.Add(new DataPerPeriod { Name = String.Join("", b),
Lines = new List<IEnumerable<string>>() });
}
else
{
a.Last().Lines.Add(b);
}
return a;
});
Result is:
Not pure LINQ, but with the help of the little "LINQ spirit" custom generic extension method which allows you to split (partition) a sequence based on condition:
public static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, Func<T, bool> splitOn)
{
using (var e = source.GetEnumerator())
{
for (bool more = e.MoveNext(); more;)
{
var group = new List<T> { e.Current };
while ((more = e.MoveNext()) && !splitOn(e.Current))
group.Add(e.Current);
yield return group;
}
}
}
}
the concrete issue can easily be solved with something like this:
IEnumerable<IEnumerable<string>> source = ...;
var result = source
.Split(e => e.FirstOrDefault() == "Period")
.Select(g => new
{
Key = g.First().Skip(1).FirstOrDefault(),
Elements = g.Skip(1)
});
Not particularly elegant (but then, neither is your dataset) but this works:
public static Dictionary<IEnumerable<string>,IEnumerable<IEnumerable<string>>> Parse(IEnumerable<IEnumerable<string>> input)
{
IEnumerable<string> key = null;
var rows = new List<IEnumerable<string>>();
var result = new Dictionary<IEnumerable<string>,IEnumerable<IEnumerable<string>>>();
foreach(var row in input)
{
if(row.First().StartsWith("Period"))
{
if(key != null)
result.Add(key,rows.AsEnumerable());
key = row;
rows = new List<IEnumerable<string>>();
}
else
{
rows.Add(row);
}
}
result.Add(key,rows);
return result;
}
Live example: http://rextester.com/ZMUM90524
I've been parsing text files for 40 years. If I can't do it nobody can. My solution is almost the same as Jamiec just a little different in style
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication43
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
StreamReader reader = new StreamReader(FILENAME);
string inputLine = "";
Dictionary<string, List<string>> data = new Dictionary<string, List<string>>();
List<string> period = null;
while ((inputLine = reader.ReadLine()) != null)
{
inputLine = inputLine.Trim();
if (inputLine.Length > 0)
{
if (inputLine.StartsWith("Period"))
{
string key = inputLine.Replace("|", "");
period = new List<string>();
data.Add(key, period);
}
else
{
period.Add(inputLine);
}
}
}
}
}
}
For a school project I am making an RPN calculator. This calculator has an abstract class Stack where three different implementations of stacks derive from. One of them is a linked list stack. For these stacks I have to show what values are on the stack. To do this I use an array. For my arraystack and list stack it was easy, but I can't figure out how to convert a linked list to an array. What is the best way to do that?
This is the code that I use for my linked list.
public class Node
{
public int data;
public Node next;
public Node(int i)
{
data = i;
next = null;
}
public void Add(int i)
{
if (next == null)
{
next = new Node(i);
}
else
{
next.Add(i);
}
}
}
public class MyLinkedList
{
private Node headNode;
private int count;
public MyLinkedList()
{
headNode = null;
count = 0;
}
public int Count()
{
return count;
}
public void Add(int i)
{
if (headNode == null)
{
headNode = new Node(i);
}
else
{
headNode.Add(i);
}
count++;
}
Implement IEnumerable on your LinkedList
using System.Linq;
Call ToArray on the LinkedList.
Implementing IEnumerable is trivial. Simply start at the root node in your list, yield return Node.data;, and move to the next node. Rinse and repeat until the next node is null.
Add a new method to your class.
public class MyLinkedList
{
... keep existing methods here ...
public int[] ToArray() {
var result = new int[count]();
var index = 0;
var node = headnode;
while (node != null) {
result[index] = node.data;
node = node.next;
}
return result;
}
Eh... Something like that?
public class MyLinkedList {
...
public Node[] ToArray() {
// You´ve got pre-computed count - let´s use it
Node[] result = new Node[count];
Node node = headNode;
for (int i = 0; i < result.Length; ++i) {
result[i] = node;
node = node.next;
}
return result;
}
}
P.S. public fields like next in the Node class is a bad practice. Convert them into properties
As #Will suggested, I would implement IEnumerable<int> by your class. That will bring you to powerful world of LINQ where you will be able to convert your linked list to array, list, or just filter nodes:
public class MyLinkedList : IEnumerable<int>
{
// your code here
public IEnumerator<int> GetEnumerator()
{
Node current = headNode;
while(current != null)
{
yield return current.data;
current = current.next;
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Now you can use all LINQ extensions with your class:
MyLinkedList myList = new MyLinkedList();
myList.Add(10);
myList.Add(15);
myList.Add(20);
int[] array = myList.ToArray();
List<int> list = myList.ToList();
// items above 13
var items = myList.Where(i => i > 13);
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Implementing C# IEnumerable<T> for a LinkedList class
After searching the web for some hours now I still can't understand how IEnumerable/IEnumerator works and how to implement it.
I've constructed a simple LinkedList from scratch but now I want to implement IEnumerable for it so I can foreach it. How do I do that?
class Program
{
LL myList = new LL();
static void Main()
{
var gogo = new Program();
}
public Program()
{
myList.Add("test");
myList.Add("test1");
foreach (var item in myList) //This doesn't work because I havn't implemented Ienumerable
Console.WriteLine(item);
Console.Read();
}
}
class LL
{
private LLNode first;
public void Add(string s)
{
if (this.first == null)
this.first = new LLNode() { Value = s };
else
{
var node = this.first;
while (node.Next != null)
node = node.Next;
node.Next = new LLNode() { Value = s };
}
}
class LLNode
{
public string Value { get; set; }
public LLNode Next { get; set; }
}
It's really not that hard. To implement IEnumerable you just need to implement the GetEnumerator method.
To do that you need to create another class that implements IEnumerator. Implementing IEnumerator is pretty easy. Generally you will pass a reference to your collection when you create the enumerator (in GetEnumerator) and the enumerator will keep track of which item is the current item. Then it will provide MoveNext which just changes the Current to the next item (and returns false if it's at the end of the list) and Reset which just sets the Current back to before the first node.
So in very broad, untested code terms, you need something like:
public class MyLinkedListEnumerator : IEnumerator
{
private LL myList;
private LLNode current;
public object Current
{
get { return current; }
}
public MyLinkedListEnumerator(LL myList)
{
this.myList = myList;
}
public bool MoveNext()
{
if (current == null) {
current = myList.first;
}
else {
current = current.Next;
}
return current != null;
}
public void Reset()
{
current = null;
}
}
What you need to do is:
(1) Make your class implement IEnumerable<T> where T is the type of the enumerated items. (In your case, it looks like it would be LLNode).
(2) Write a public IEnumerator<T> GetEnumerator. Implement it using the "yield" keyword.
(3) Add a IEnumerator IEnumerable.GetEnumerator() method and just return GetEnumerator().
The following code should make this clear. Where I have <int>, you should put <LLNode>, assuming that is the correct type.
using System;
using System.Collections;
using System.Collections.Generic;
namespace Demo
{
internal class Program
{
private static void Main()
{
var test = new MyDemo();
foreach (int item in test)
{
Console.WriteLine(item);
}
}
}
public class MyDemo: IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
// Your implementation of this method will iterate over your nodes
// and use "yield return" to return each one in turn.
for (int i = 10; i <= 20; ++i)
{
yield return i;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
I would have modified your code to do it properly, but the code you posted won't compile.
[EDIT]
Now you've updated your code, I can see that you want to enumerate the values. Here's the completed code:
using System;
using System.Collections;
using System.Collections.Generic;
namespace Demo
{
internal class Program
{
private LL myList = new LL();
private static void Main()
{
var gogo = new Program();
}
public Program()
{
myList.Add("test");
myList.Add("test1");
foreach (var item in myList) // This now works.
Console.WriteLine(item);
Console.Read();
}
}
internal class LL: IEnumerable<string>
{
private LLNode first;
public void Add(string s)
{
if (this.first == null)
this.first = new LLNode
{
Value = s
};
else
{
var node = this.first;
while (node.Next != null)
node = node.Next;
node.Next = new LLNode
{
Value = s
};
}
}
public IEnumerator<string> GetEnumerator()
{
for (var node = first; node != null; node = node.Next)
{
yield return node.Value;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private class LLNode
{
public string Value { get; set; }
public LLNode Next { get; set; }
}
}
}
I have to implement a call graph for expressions like Id = Id(Param); and that wasn't a problem.
Now I have to implement an enumerator which lists one at a time all topological orderings among the calls that satisfy the order of dependencies.
And here's the trouble.
This is a simple node for the call graph:
class CallGraphNode
{
private string name;
public List<CallGraphNode> dependents = new List<CallGraphNode>();
public int dependencies;
private bool executed = false;
public bool Executable { get { return dependencies == 0; } }
public bool Executed { get { return executed; } set { executed = value; } }
public CallGraphNode(string name)
{
this.name = name;
dependencies = 0;
}
public override string ToString()
{
return name;
}
public void AddDependent(CallGraphNode n)
{
dependents.Add(n);
}
}
And this is the call graph class itself:
class CallGraph : IEnumerable<List<CallGraphNode>>
{
public List<CallGraphNode> nodes = new List<CallGraphNode>();
public void AddNode(CallGraphNode n)
{
nodes.Add(n);
}
public static void Show(IEnumerable<CallGraphNode> n)
{
foreach (CallGraphNode node in n)
{
Console.Write("{0} ", node);
}
Console.WriteLine();
}
static IEnumerable<List<CallGraphNode>> EnumerateFunctions(List<CallGraphNode> executable, List<CallGraphNode> res)
{
if (executable.Count == 0)
yield return res;
else foreach (CallGraphNode n in executable)
{
if (!n.Executed)
res.Add(n);
List<CallGraphNode> next_executable = new List<CallGraphNode>(executable);
executable.Remove(n);
foreach (CallGraphNode m in n.dependents)
if (--m.dependencies == 0)
next_executable.Add(m);
foreach (List<CallGraphNode> others in EnumerateFunctions(next_executable, res))
yield return others;
foreach (CallGraphNode m in n.dependents)
m.dependencies++;
if (!n.Executed)
res.Remove(n);
}
}
IEnumerator<List<CallGraphNode>> IEnumerable<List<CallGraphNode>>.GetEnumerator()
{
List<CallGraphNode> executable = new List<CallGraphNode>();
foreach (CallGraphNode n in nodes)
if (n.Executable || n.Executed)
executable.Add(n);
List<CallGraphNode> output = new List<CallGraphNode>();
foreach (List<CallGraphNode> list in EnumerateFunctions(executable, output))
yield return list;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{ throw new NotImplementedException(); }
}
Now, the problem is it just won't work. When I try to create an IEnumerator and assign it the GetEnumerator() return value, I get a casting error and that's honestly what I expected when trying to do so:
IEnumerator<List<CallGraphNode>> lt = cg.GetEnumerator();
Then I've tried:
System.Collections.Generic.List<CallGraphNode>.Enumerator en = cg.nodes.GetEnumerator();
This works, but the method EnumerateFunctions is never called and the enumerator just contains the original list of graph nodes.
Any ideas?
The problem is that you're implementing both IEnumerable<T> and IEnumerable using explicit interface implementation.
You probably want to change this declaration:
IEnumerator<List<CallGraphNode>> IEnumerable<List<CallGraphNode>>.GetEnumerator()
to be a "normal" interface implementation:
public IEnumerator<List<CallGraphNode>> GetEnumerator()
Alternatively, you could stick with explicit interface implementation, but use:
IEnumerable<List<CallGraphNode>> sequence = cg;
IEnumerator<List<CallGraphNode>> lt = sequence.GetEnumerator();
I need to access the current and previous element in an IQueryable object. If I had an int array, I would do the following:
var array = new int[]{0,1,2,3,4};
for(var i = 1; i<array.Length ; i++)
{
method1(array[i-1], array[i]);
}
I don't know to do the same with IQueryable, since it does not implement IList.
Using extension methods makes this fairly easy.
public static class IEnumerableExtensions
{
public static IEnumerable<ValueWithPrevious<T>> WithPrevious<T>(this IEnumerable<T> #this)
{
using (var e = #this.GetEnumerator())
{
if (!e.MoveNext())
yield break;
var previous = e.Current;
while (e.MoveNext())
{
yield return new ValueWithPrevious<T>(e.Current, previous);
previous = e.Current;
}
}
}
}
public struct ValueWithPrevious<T>
{
public readonly T Value, Previous;
public ValueWithPrevious(T value, T previous)
{
Value = value;
Previous = previous;
}
}
Usage:
var array = new int[] { 1, 2, 3, 4, 5 };
foreach (var value in array.WithPrevious())
{
Console.WriteLine("{0}, {1}", value.Previous, value.Value);
// Results: 1, 2
// 2, 3
// 3, 4
// 4, 5
}
You can turn an IQueryable<> into a List<> using ToList<>().
EDIT
Misread the question a bit. This code will give you consequetive elements
public static IEnumerable<Pair<T,T>> GroupIntoConsequetive(this IEnumerable<T> enumerable) {
using ( var e = enumerable.GetEnumerator() ) {
if ( !e.MoveNext() ) {
yield break;
}
var last = e.Current;
while ( e.MoveNext() ) {
yield return new Pair<T,T>(last, e.Current);
last = e.Current;
}
}
}
I'm not sure there is default way but writing an extension method to do so shouldn't be to difficult. I'm assuming there is a simple Pair implementation
public static IEnumerable<Pair<T,T>> Window(this IEnumerable<T> enumerable) {
using ( var e = enumerable.GetEnumerator() ) {
while ( e.MoveNext() ) {
var first = e.Current;
if ( !e.MoveNext() ) {
throw new InvalidOperationException("Need even number");
}
var second = e.Current;
yield return new Pair<T,T>(first,second);
}
}
}
With the window you could then get the behavior you desire with the following
var col = GetQueryableItem();
col.Window().Select(pair => method1(pair.First, pair.Second));
Quick and dirty Pair implementation
public struct Pair<T1,T2> {
public readonly T1 First;
public readonly T2 Second;
public Pair(T1 first, T2 second) {
First = first;
Second = second;
}
}
But it provides extension methods to create an array or a list from your IQueryable<T> instance, see ToArray() and ToList(). You can then go and do the same as you would with the array in your example.
IQueryable is IEnumerable. So you can do something like:
var a = new [] {1, 2, 3, 4}.AsQueryable();
if (a.Count() < 2) {
return;
}
var prev = a.First();
var isFirst = true;
foreach (var i in a) {
if (isFirst) {
isFirst = false;
continue;
}
method1(prev, i);
prev = i;
}
Or simply convert IQueryable into IList:
var list = a.ToList();