views:

436

answers:

5

I've been searching for the standard implementation of a doubly linked list in c# (so that I have a linked list I can iterate over backwards) and cannot find one. I feel like something so simple must have an implementation that I'm just missing.

If it does exist, for which version of c#/.net does it exist?

Reverse iteration in general seems to be something not intended to be done in c#. Is my mind just stuck too much in c++/stl mode or is this something sorely lacking in c#?

I'm aware of LinkedList but in failing to find a way to iterate over it backwards had assumed it was singly linked.

If LinkedList is doubly linked how does one go about iterating over it backwards (Efficiently)?

+2  A: 

Yes, it does. Check out the LinkedList class which is part of the System.Collections.Generic namespace. The documentation provides a decent sample to get you started.

EDIT: reversing with a LinkedList using the ElementAt extension method:

string[] words = { "the", "fox", "jumped", "over", "the", "dog" };

LinkedList<string> list = new LinkedList<string>(words);
for (int index = list.Count - 1; index >= 0; index--)
{
    Console.WriteLine(list.ElementAt(index));
}

As others have noted, this isn't the most efficient solution. The proper way is to use the data structure's intended properties. See spender's answer.

Ahmad Mageed
I don't want to create a new list. I want to iterate backwards over an existing one in place. In my case the performance is an issue.
Catskul
@Catskul that was just to demonstrate reversing over a regular list. I just edited a 2nd time showing how to iterate backwards with a `LinkedList`
Ahmad Mageed
ElementAt will be extremely inefficient for most implementations. The documentation makes no reference to them using any tricks to make it not so.
Catskul
Surely with a LinkedList, using the ElementAt extension will be horribly inefficient. LinkedList isn't designed for random access, rather it is designed for quick iteration and cheap insertion.
spender
That code is so much easier to understand than List.Contains() !!!
Mitch Wheat
See my answer for a more efficient approach.
spender
I didn't say it was the best and I agree about the inefficiency.
Ahmad Mageed
+2  A: 

How about System.Collections.Generic.LinkedList()

Here are the docs on MSDN:

http://msdn.microsoft.com/en-us/library/he2s3bh7.aspx

Version Info
.NET Framework: Supported in: 3.5, 3.0, 2.0
.NET Compact Framework: Supported in: 3.5, 2.0
XNA Framework: Supported in: 3.0, 2.0, 1.0

That said, I am with the others that it is generally preferrable to use a higher abstraction when working with such a rich framework.

JohnFx
I have a specific need to be able to iterate over the list backwards, and to have cheap inserts + cheap reordering.
Catskul
Okay, then the first part of my answer should help you.
JohnFx
RTFM is a not helpful especially since the docs do not specifically deal with reverse iteration. If we're just going to tell everyone to RTFM then why have Stackoverflow at all?
Catskul
That is hardly a RTFM. You asked for the .net implementation of doubly linked lists and I gave you the name of the relevant framework object, answered your question about what versions of the framework support it and gave you a link to the documentation on it. You never asked for code to show reverse iteration, you just mused about whether it was intended to be done. The only question I didn't answer is the "Is my mind just stuck..." which I took as rhetorical.
JohnFx
Sorry I mis-interpreted you. The *"Okay, then the first part of my answer should help you"* response to my iteration commend seemed like an RTFM.
Catskul
+1  A: 

How about LinkedList?

kenny
How do you efficiently iterate over it backwards?
Catskul
while (nodeP != null) nodeP = nodeP.Previous;
kenny
+10  A: 

The following code will efficiently iterate over a LinkedList in reverse:

        LinkedList<string> list = new LinkedList<string>
            (new[] {"cat", "dog", "frog", "antelope", "gazelle"});
        LinkedListNode<string> item = list.Last;
        do
        {
            Console.WriteLine(item.Value);
            item = item.Previous;
        }
        while (item != null);
        Console.ReadKey();

The key here is that a LinkedList contains reference to only the First and Last LinkedListNode instances of the list. Each LinkedListNode instance holds a reference to the next and previous item in the list (or null at each end of the list) and also a Value property. This means iteration from the first or last LinkedListNode is easy, but random access requires iteration from the first or last in the list.

If you need to make an insertion along the way, use LinkedList.AddBefore or AddAfter to insert a new LinkedListNode.

spender
Thats what I had been looking for. For some reason I was under the impression that List<T>.Last would return something of type T.Thank you. Somehow you are the only person who seems to have understood the problem or even the concepts behind linked lists at all : /
Catskul
A much underrated container. Glad to help.
spender
This will throw an ArgumentNullException if the list is empty. Changing the do/while loop to a (simpler to read, IMO) while loop will solve the problem - see my answer for an example.
Jon Skeet
Yeah, I saw that and just converted to a while loop in my head without considering the implications of do/while.
Catskul
+6  A: 

As well as the answers given here, you can write an extension method to LinkedList<T> to make this slightly easier to reuse:

public static IEnumerable<T> Backwards(this LinkedList<T> list)
{
    LinkedListNode<T> node= list.Last;
    while (node != null)
    {
        yield return node.Value;
        node = node.Previous;
    }
}

Use with:

foreach (string x in list.Backwards())
{
    // ...
}
Jon Skeet
Little typo: `LinkedListNode<string>` should be `LinkedListNode<T>`
Oliver
@Oliver: thanks, fixed.
Jon Skeet
Thanks. I'm a little confused why something like this isn't just in the standard lib already.
Catskul
@Catskul here's a good link that explains that http://blogs.msdn.com/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx.
Matt Warren
@Matt: Thanks. IMHO though, iterating backwards over a list is a more basic functionality than the "ForEach" discussed there (e.g. backwards iteration is provided by most STL containers) and in as much as it's not there, it almost seems like the C# creators were suggesting you shouldn't be doing it. In C#, even when I know how to do something by implementing it myself, I feel like if I didn't find a simple way, I must have missed something/be doing something wrong.
Catskul