CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Dec 2009
    Posts
    48

    Arrow Change Item in a LinkedList

    I have a list and I want to change one item for another

    Code:
            public void ActualizarProduto(Produto obj)
            {
                foreach (Produto tmp in ListProdutos)
                {
                    if (obj.Text == tmp.Text)
                    {
                        tmp = obj;
                        return;
                    }
                }
            }
    it seems I can't use tmp = obj because it is a foreach;
    (btw: it will only find one result - there is only on item with same text)

    If you have any ideia, it would be very helpful thank you in advance

  2. #2
    Join Date
    Jun 2008
    Posts
    2,477

    Re: Change Item in a LinkedList

    You cannot change objects in a linked list because you will destroy the current state of the iterator. If you need to do that, you can use LINQ, a regular for loop (careful here), or make a temporary list of objects to change and then do the swapping after the foreach loop.

  3. #3
    Join Date
    Mar 2004
    Location
    33°11'18.10"N 96°45'20.28"W
    Posts
    1,808

    Re: Change Item in a LinkedList

    Quote Originally Posted by BigEd781 View Post
    You cannot change objects in a linked list inside a foreach loop because you will destroy the current state of the iterator...
    forgot a part.

  4. #4
    Join Date
    Jan 2010
    Posts
    1,133

    Re: Change Item in a LinkedList

    Ok. Assuming that your Produto is a reference type (a class, not a struct), and that ListProdutos is List<Produto>, here’s why it doesn’t work.

    The tmp variable obtains a reference to the object in the list. With tmp, you can alter the state of the referenced object (the one in the list), or call some of it’s methods.

    Now, when
    tmp = obj
    is executed, tmp references a NEW object, and has no connection to the one in the list. You just change the REFERENCE.

    Suppose it’s the first object in the list:



    [tmp]---(ref: L1)---------> [L1] [L2][L3][L4]



    This turns to:



    [tmp]---(ref: obj)--------->[obj]

    [L1][L2][L3][L4]



    You can use the for loop and the indexer to access the object IN THE LIST directly, and then change it.

    Code:
    for (int i = 0; i < ListProdutos.Count; i++)
    {
    	if (obj.Text == ListProdutos[i].Text)
                    {
                         ListProdutos[i] = obj;
                         return;
                    }
    }
    Last edited by TheGreatCthulhu; January 9th, 2010 at 03:05 PM. Reason: readability

  5. #5
    Join Date
    Jan 2010
    Posts
    1,133

    Re: Change Item in a LinkedList

    Here's a simple example:

    Code:
    
        public class MyClass
        {
            public int value = 0;
    
            public MyClass(int val)
            {
                value = val;
            }
        }
    
        class Program
        {        
            static void Main(string[] args)
            {
                List<MyClass> list = new List<MyClass>();
                
                for (int i = 0; i < 5; i++)         
                    list.Add(new MyClass(i));
    
                MyClass obj = new MyClass(-12);   // just a random number I picked...
    
                MyClass tmpRef = list[3];
    
                list[2] = obj;      // affects the list.
                tmpRef = obj;    // the list is not affected!
    
                for (int i = 0; i < list.Count; i++)
                    Console.WriteLine(list[i].value.ToString());
            }
        }
    And the output:
    Code:
    0
    1
    -12
    3
    4
    Press any key to continue . . .

  6. #6
    Join Date
    Mar 2004
    Location
    33°11'18.10"N 96°45'20.28"W
    Posts
    1,808

    Re: Change Item in a LinkedList

    foreach uses the iterator pattern. behind the scenes it's implemented as a while(iEnumerator.MoveNext()) internally it keeps a version number which is changed when you add or remove items in the list, and when you remove an item it throws an exception because it's being iterated and the version changes (which it wont allow).

  7. #7
    Join Date
    Jan 2010
    Posts
    1,133

    Re: Change Item in a LinkedList

    Oh, your code won’t compile. Slipped that detail of my mind…
    But, my point is – bear in mind that you’re working with object references.

    Anyway, the Iterator pattern enables you to access elements of a collection, without the need to worry about the way the collection is implemented. You can treat arrays, lists, hash tables, or any implementation of IEnumerable the same way. The way it works is that any IEnumerable object creates it’s version (implementation) of IEnumerator on request, and the client code (you, via foreach) just uses the IEnumerator interface.

    Now, the compiler won’t allow you to change the variable declared in the foreach loop’s “header”, since it has “read-only context” (MSDN help on the error), and even if it did, you wouldn’t change the underlying list. And it’s a good thing it won’t let you do it. The compiler prevented you to create a weird bug.
    I’m just not sure what exactly the foreach block turns into after the compilation, but as the others have said – it would probably make the IEnumerator instance invalid.

    The foreach looks nicer, but why not use the for loop? Unless there is a good reason for all that indirection/flexibility? If you are concerned about the design and reusability, if at some point in the future you decide to change the type of the underlying collection, then this might become a problem (but maybe it won’t – only you can tell).
    Last edited by TheGreatCthulhu; January 9th, 2010 at 04:45 PM.

  8. #8
    Join Date
    Jan 2010
    Posts
    1,133

    Re: Change Item in a LinkedList

    I only now noticed the title. You’re using a LinkedList…
    I didn’t pay attention, sorry.
    Here’s the same example as before, except it now uses a LinkedList.

    Code:
    static void Main(string[] args)
    {
          LinkedList<MyClass> list = new LinkedList<MyClass>();
    
          for (int i = 0; i < 5; i++)
                list.AddLast(new MyClass(i));
    
          MyClass obj = new MyClass(-12);   // just a random number I picked...
    
          LinkedListNode<MyClass> node = list.First;            
          for (int i = 0; i < list.Count; i++)
          {
                if (i == 2)   
                {
                       // If you just make the (current) node reference something else,
                       // you'll create a list that's in an inconsistent state
                       // (since Previous & Next will be null)!
    
                       // This effectively replaces the current node. 
                       list.AddAfter(node, obj);
                       LinkedListNode<MyClass> addedNode = node.Next;
                       list.Remove(node);
    
                       node = addedNode;  // this makes the WriteLine() work
                }
    
                Console.WriteLine(node.Value.value.ToString());
                node = node.Next;
          }
    }

    Output:

    0
    1
    -12
    3
    4
    Press any key to continue . . .

    I hope it helps.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured