How to populate Lists within Lists, using for loops, clearing and selecting data. (passing by reference issue)

lm1212 141 Reputation points
2022-08-25T09:39:15.97+00:00

I am having trouble with List and Array in c# , trying to create a simple program which should return a list which contains another list. It requires two for loops, the outer loop has 3 iterations, the second loop 5.
I cannot find a way to get around either A: the null initialization with arrays, or B: the reference issue with c# as I cannot effectively Clear() the list.

The program looks like this:

FarmResults fr= new FarmResults ();  
fr.startingAmount = 5;  
fr.seriesAmount= 5;  
fr.simulationAmount = 3;  
  
fr.doSeries(fr);  
  
  
namespace SImpleConsoleApp  
{  
  
    public class FarmResults   
    {  
        public int startingAmount { get; set; }  
        public int seriesAmount{ get; set; }  
        public int simulationAmount { get; set; }  
  
        public void doSeries(FarmResults fr)  
        {  
            int sa= fr.seriesAmount;  
            int sta= fr.startingAmount ;  
            int sims = fr.simulationAmount ;  
  
            Random ran = new Random();  
  
            int sur;  
            int die;  
  
            List<List<Chickens>> sim = new List<List<Chickens>>();  
            List<Chickens> fare= new List<Chickens>();  
  
  
            for (int s = 0; s < sims; s++)  
            {  
                for (int b = 0; b < sa; b++)  
                {  
  
                    int survived= ran.Next(100);  
                    if (survived< 60)  
                    {  
                        sur += 1;  
                        sta+= 1;  
                    }  
                    else  
                    {  
                        die += 1;  
                        sta -= 1;  
                    }  
                    fare.Add(new Chickens{ chickens = sta, saved= sa, died= die  });  
                }  
                    sim.Add(fare);  
                  
                fare.Clear();  
            }  
        }  
    }  
  
        public class Chickens  
        {  
        public int chickens = 0;  
        public int saved= 0;  
        public int died= 0;  
  
        }  
  
}  

So upon successful compeletion of the code above (which it does not do yet) I want the list of sims to have 3 elements, of which each contains 5 elements.
The problem is I cannot find a way to populate the lists correctly. In this example, the element at position 1 in the sim list, will contain 5 after elements after 1 completion of the second loop, then it will contain 10 after the second iteration, 15 after the third. The items in the fare list do not clear (passing by reference), to allow the second element in the sims list to receive a new list (or cleared one.)

Does anyone know which approach to use to populate the Lists as intended? Thank you.

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,279 questions
{count} votes

Accepted answer
  1. Viorel 112.5K Reputation points
    2022-08-28T13:20:23.157+00:00

    In the original code,

    sim.Add(fare);  
    fare.Clear();  
    

    the list that was just added to sim is cleared, therefore the data are lost.

    If you execute sim.Add(fare.ToList( )), a new list is created by ToList, which is a copy of fare; it is also added to sim. Therefore, fare.Clear does not clear the added list.

    Two lists having the same data will exist for a short period of time. It is more efficient to do something like this:

    for( int s = 0; s < sims; s++)  
    {  
       List<Chickens> fare= new List<Chickens>( );  
       for( int b = 0; b < sa; b++)  
       {  
          . . .  
       }  
       sim.Add( fare);  
    }  
    

    In this code:

    List<Chickens> fare2 = new List<Chickens>();  
    fare2 = fare;  
    sim.Add(fare2)  
    fare.Clear();  
    

    a new empty list is created, but then fare2 is repointed to the list that is referenced by fare. The new list is lost. Both of fare2 and fare now represents the same list object, because fare2=fare does not create a copy of the list. Then fare.Clear deletes the data (similar to fare2.Clear). This is not suitable.


2 additional answers

Sort by: Most helpful
  1. Jack J Jun 24,296 Reputation points Microsoft Vendor
    2022-08-26T02:42:17.303+00:00

    @lm1212 , Welcome to Microsoft Q&A, based on my test, I find that we need to adjust the position of the code fare.Clear();.

    You could try to place it before the second loop, like the following code:

     for (int s = 0; s < sims; s++)  
                {  
                    fare.Clear();  
                    for (int b = 0; b < sa; b++)  
                    {  
                        int survived = ran.Next(100);  
                        if (survived < 60)  
                        {  
                            sur += 1;  
                            sta += 1;  
                        }  
                        else  
                        {  
                            die += 1;  
                            sta -= 1;  
                        }  
                        fare.Add(new Chickens { chickens = sta, saved = sa, died = die });  
                    }  
                    
                    sim.Add(fare);  
      
                     
                }  
    

    After testing the above code, the following picture will get your target result:

    235019-image.png

    Best Regards,
    Jack


    If the answer is the right solution, please click "Accept Answer" and upvote it.If you have extra questions about this answer, please click "Comment".
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

  2. lm1212 141 Reputation points
    2022-08-28T09:47:15.137+00:00

    @Viorel
    Thank you for your reply Viorel.
    Your solution of using To.List() works. Though it is why it works that I am confused:
    fare is already a list, so I don't understand why the ToList() is a method available for it
    to use, and why anyone would want to convert a List to a List (converting to the same thing
    does not appear to have make any sense to me.) There is also nothing written in the ToList() method
    description that describes an outcome or action which I am after to complete my problem. This way of solving
    my problem I do not see as intuitive, and knowledge of the underlying
    tools (List and how they operate) is therefore required in order to complete this task. - If anyone can give a brief
    explanation to this, or link to the educational resource which explains this for me it is most
    appreciated.

    If I try:

    ......  
    fare.Add(new Chickens{ chickens = sta, saved= sa, died= die  });  
                     }  
    List<Chickens> fare2 = new List<Chickens>();  
    fare 2 = fare;  
    sim.Add(fare2)  
    fare.Clear();  
    

    fare is passed by reference, not value, so the properties in fare2 (or fare if I use that) originally assigned to sim
    do whatever happens when I alter the properties in fare. - So they clear, when I call .Clear() on fare.
    To me this seems the most obvious way of completing the task, but the pass by value/reference issue
    prevents this.

    @Jack J Jun
    Thank you for your reply. I tried the solution you offered and my code is producing the exact same output as before (The list in sim still clears after clearing fare in the first loop).
    I suspect you have changed something else elsewhere?

    Kind regards.