I agree with Marc's comment saying that this type system is non-sense. Still, you can solve it with delegates. That's a bit of cheating, because basically they are nothing more than methods, but here we go.
I agree with Marc's comment saying that this type system is non-sense. Still, you can solve it with delegates. That's a bit of cheating, because basically they are nothing more than methods, but here we go: void PrintFamily(Ancestor a) { Action printParent = null; printParent = (parent, level) => { var indentation = new string(' ', level * 4); var indentationChildren = new string(' ', (level + 1) * 4); Console.
WriteLine(indentation + parent. Name); foreach(var child in parent. Children) { if(child is Child) Console.
WriteLine(indentationChildren + child. Name); else if(child is Parent) { printParent((Parent)child, level + 1); } } }; printParent(a, 0); }.
1 Clever use of delegates to get around the requirements. Hopefully it's not considered cheating! :) – George Duckett Dec 12 at 10:13 You could use new string(char, count) instead of enumerable.
Repeat though. – George Duckett Dec 12 at 10:16 @GeorgeDuckett: Thanks for the hint. That's much better – Daniel lgarth Dec 12 at 10:17 I feel a bit better because I'd never have got that in a million years due to my ignorance of the Action delegate.
Perhaps I'm not as code-stupid as I feared, but commonsense stupid enough not to keep up to speed with the . Net framework. Thank you very much.
– 5arx Dec 12 at 10:42.
This is horrible, but within the scope of the question (no extra methods, so can't add polymorphism/discriminator, and method must take Ancestor, so no method recursion): static void Write(Ancestor root) { // stack since depth-first var stack = new Stack>(); stack. Push(Tuple. Create((Person)root, 0)); while(stack.
Count > 0) { var pair= stack.Pop(); var person = pair. Item1; // indentation Console. Write(new string('\t', pair.
Item2)); Parent parent = person as Parent; // node markers aren't fully specified, but this gets somewhere // near; maybe * should actually be checking Children! = null && // Children. Count > 0 if(person == root) {} else if (parent!
= null) { Console. Write("*");} else {Console. Write("-");} Console.
WriteLine(person. Name); // recursion on the stack if(parent! = null && parent.
Children! = null) { foreach(var next in Enumerable. Reverse(parent.
Children)) { stack. Push(Tuple. Create(next, pair.
Item2 + 1)); } } } }.
Here's my go, using a stack to emulate recursion: static void PrintTree(Ancestor ancestor) { Stack> PersonStack = new Stack>(); PersonStack. Push(new Tuple(0, ancestor)); while (PersonStack. Count!
= 0) { Tuple NextPerson = PersonStack.Pop(); Console. WriteLine(new string(' ', NextPerson. Item1) + NextPerson.
Item2. Name); Parent NextPersonAsParent = NextPerson. Item2 as Parent; if (NextPersonAsParent!
= null && NextPersonAsParent. Children! = null) { foreach (var Child in NextPersonAsParent.
Children) { PersonStack. Push(new Tuple(NextPerson. Item1 + 1, Child)); } } } }.
With a little bit of "cheating" (thanks daniel for the ides" this uses recursion and stays with in the constraints of the task. DISCLAIMER this more proves that the class hierachi proposed is odd. Especially for the task and I wouldn't use this technique in production internal static string ToString(Ancestor root){ Func inner = (x, y) => string.
Empty; inner = (p, indentation) =>{ var parents = p.Children.OfType(); var children = p.Children.OfType(); var childString = string. Concat (children. Select (c => indentation + "-" + c.Name + Environment.
NewLine)); return indentation + "-" + p. Name + Environment. NewLine + childString + string.
Concat (parents. Select(par => inner(par, " " + indentation))); }; return inner(root, string. Empty); } Firstly we declare a functor and initialize with a dummy value.
Then we construct a lambda expression that can call it self recursively. The body of the expression does the same as the below method. If the method signatur did not require an ancestor we could have done something like: internal string ToString(Parent parent, string indentation){ var parents = parent.Children.OfType(); var children = parent.Children.OfType(); var childString = children.
Select(c => indentation + "-" + c. Name + Environment. NewLine); return indentation + "-" + parent.
Name + Environment. NewLine + childString + string. Concat(parents.
Select(par => ToString(par, " " + indentation))); } first create a list of all parent and one of all children. Then create the string for all the children (where no recursion is needed) and the recurs for all parents.
Edit: A polymorphic solution is most likely the simplest, but you need to be able to alter the objects. Have Person implement a virtual method: Print() for instance, which would be overridden in Parent in order to printout the children. Indentation could be handled by supplying an indentation-level argument for instance.As you have noted, the constraints of the problem prohibit this.
The object structure provided in the question is rather senseless, and the constraints rather narrow. Also, the fact that you need to implement a method that takes an Ancestor and are limited to only that method body, leads me to think that the question was asked specifically to lead you towards the stack approach. Additionally, the latter has important performance benefits when compared to recursion.
There are a couple of good stack examples already, so I would suggest an alternate recursion approach, that in principle should fit the 'don't declare any extra methods'-rule, and is much more readable ( if you know your lambda's :) Action, int> traverseAndPrint = null; traverseAndPrint = (ps, i) => { foreach (var p in ps) { Console. WriteLine("{0}-{1}", new string(' ', i), p.Name); if (p is Parent) traverseAndPrint(((Parent)p). Children, I + 1); } }; traverseAndPrint(new {ancestor}, 0).
Altering the objects is not an option. Can you elaborate on the recursion and stack--based solutions please? The other, no doubt excellent responses are way over my head :-( – 5arx Dec 12 at 10:11.
If you're allowed to (re)create objects and exploit their simplicity you could use this: private static void PrintAncestor(Ancestor myAncestor) { Console. WriteLine(myAncestor. Name); foreach (var child in myAncestor.
Children) { string intend = new string(myAncestor.Name. TakeWhile(c => c == '\t').ToArray()) + '\t'; if (child is Ancestor) PrintAncestor(new Ancestor { Children = (child as Ancestor). Children, Name = intend + child.Name }); if (child is Parent) PrintAncestor(new Ancestor { Children = (child as Parent).
Children, Name = intend + "- *" + child. Name }); if (child is Child) Console. WriteLine(intend + "- " + child.
Name); } } prints: GrandDad - Aunt - Uncle - *Dad - Me - Sister.
Internal void ToString(Ancestor root) { Trace. WriteLine(root. Name); Trace.Indent(); foreach(var child in root.
Children) { if(child is Parent) ToString(new Ancestor(){Name = child. Name, Children = child. Children}); else Trace.
WriteLine(child. Name); } Trace.Unindent(); }.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.