0

I send a list of objects List<solutions> "_solutions" to a method as argument, then I copy this argument to another list called "SOLUTIONS" and do some changes on SOLUTIONS and finally return SOLUTIONS. but when I change the SOLUTIONS, the _solution will be changed. I do not want to change the _solutions. for example after in line SOLUTIONS[pp].Route.Clear(); when pp=0 the _solution[0].Route will be clear.

static List<solutions> CrossOverB(List<solutions> _Solutions)
{
    List<solutions> SOLUTIONS = new List<solutions>();
    SOLUTIONS.AddRange(_Solutions);

    int pp = 0;
    List<int> Team1;
    List<int> Team2;

    List<int> TempOff1;
    List<int> TempOff2;
    int index1 = 0;
    double Time1 = int.MaxValue, Time2 = int.MaxValue;

    while (pp < PopulationSize)
    {
        Team1 = new List<int>();
        Team2 = new List<int>();
        TempOff1 = new List<int>();
        TempOff2 = new List<int>();
        index1 = 0;
        Time1 = int.MaxValue;
        Time2 = int.MaxValue;
        int[] MinMax = new int[2];

        int maxindex = 0, minindex = 0;
        MinMax = FindMaximumMinimumTeam(SOLUTIONS[pp].Route);
        minindex = MinMax[0];
        maxindex = MinMax[1];
        //extract maximum team from 
        Team1 = ExtractTeamFromSolution(SOLUTIONS[pp].Route, maxindex);
        //remove start and end city
        Team1.RemoveAt(0);
        Team1.RemoveAt(Team1.Count - 1);

        Team2 = ExtractTeamFromSolution(SOLUTIONS[pp].Route, minindex);
        Team2.RemoveAt(0);
        Team2.RemoveAt(Team2.Count - 1);
        //add team2 to team1
        //all cities are in team1
        Team1.AddRange(Team2);
        Team2.Clear();

        //add other teams(except max and min team) to the team2
        for (int i = 1; i < NoOfTeams + 1; i++)
        {
            if (i != maxindex && i != minindex)
            {
                Team2.AddRange(ExtractTeamFromSolution(SOLUTIONS[pp].Route, i));
            }
        }

        TempOff1.Add(StartCity);
        TempOff1.Add(endCity);
        TempOff2.Add(StartCity);
        TempOff2.Add(endCity);
        //index1 = TempOff1.Count - 1;
        //index2 = TempOff2.Count - 1;

        while (index1 != Team1.Count)
        {
            Time1 = int.MaxValue;
            Time2 = int.MaxValue;

            //fill off1
            //i want to add team1[index1] to the off1 or off2 righ befor the end city
            if (CalculateTeamTime(TempOff1, Team1.ElementAt(index1), TempOff1.Count - 2) < TMAX)
            {
                Time1 = TimeTable[TempOff1.ElementAt(TempOff1.Count - 2)][Team1.ElementAt(index1)];
            }
            if (CalculateTeamTime(TempOff2, Team1.ElementAt(index1), TempOff2.Count - 2) < TMAX)
            {
                Time2 = TimeTable[TempOff2.ElementAt(TempOff2.Count - 2)][Team1.ElementAt(index1)];
            }

            //compare time1 and time2 for the winner
            if (Time1 <= Time2 
                && TempOff1.Contains(Team1.ElementAt(index1)) == false 
                && TempOff2.Contains(Team1.ElementAt(index1)) == false  
                && Team2.Contains(Team1.ElementAt(index1)) == false
                && CalculateTeamTime(TempOff1, Team1.ElementAt(index1), TempOff1.Count - 2) < TMAX)//fill off1
            {
                TempOff1.Insert(TempOff1.Count - 1, Team1.ElementAt(index1));
                index1++;
            }
            else if (Time1 >= Time2 
                && TempOff2.Contains(Team1.ElementAt(index1)) == false 
                && TempOff1.Contains(Team1.ElementAt(index1)) == false  
                && Team2.Contains(Team1.ElementAt(index1)) == false
                && CalculateTeamTime(TempOff2, Team1.ElementAt(index1), TempOff2.Count - 2) < TMAX)//fill off2
            {
                TempOff2.Insert(TempOff2.Count - 1, Team1.ElementAt(index1));
                index1++;
            }
            else// off1 and off2 do not accept the city. so i reject the city
            {
                index1++;
            }// of else

            if (CalculateTeamTime(TempOff2)>TMAX)
            {
                Console.WriteLine();
            }

        }// of while

        SOLUTIONS[pp].Route.Clear();
        SOLUTIONS[pp].Route.AddRange(TempOff1);
        SOLUTIONS[pp].Route.AddRange(TempOff2);
        SOLUTIONS[pp].Route.AddRange(Team2);

        pp++;
    }

    return SOLUTIONS;
}
Milad
  • 83
  • 2
  • 8
  • 1
    Do you mean that the specific solution items in `_Solutions` change? This is because they are references. – smoksnes Jan 18 '17 at 11:37
  • 1
    Check this link, possible duplicate http://stackoverflow.com/questions/222598/how-do-i-clone-a-generic-list-in-c – Cleptus Jan 18 '17 at 11:38
  • We don;t know what ExtractTeamFromSolution() does, or what "will be changed" means. A good technical question has expected and actual results. Create a [mcve]. – H H Jan 18 '17 at 11:39
  • because of reference i have copied to SOLUTIONS. is there any way to prevent changing the _solutuions – Milad Jan 18 '17 at 11:41

2 Answers2

1

I'd guess that solutions is a class, right? Classes are reference types, i.e. you do not operate on actual objects, but on references to these objects.

When you call SOLUTIONS.AddRange(_Solutions); you are not really copying the objects, but you are only copying references to the objects that reside in _Solutions and store them in SOLUTIONS, but the objects remain the very same. The first object in _Solutions is exactly the same as the first object in SOLUTIONS (and so on), not a different object holding the same data.

You will have to create deep copies of the objects to overcome this issue. For example you could implement a method Copy in your solutions class

solutions Copy()
{
    return new solutions
    {
    [... copy all fields here]
    };
}

and then change the line to copy the items to

SOLUTIONS.AddRange(_Solutions.Select(s => s.Copy()));

You will have a brand new list with brand new objects, not only the boring old objects from the old list.

Paul Kertscher
  • 9,416
  • 5
  • 32
  • 57
0

You are actually copying references to the elements in your _Solutions list. Any change at element level (some property within the element) will also be visible when querying information from elements in _Solutions.

Your code

List<solutions> SOLUTIONS = new List<solutions>();
SOLUTIONS.AddRange(_Solutions);

only ensures that you have a different list of references (may be useful when you want to both iterate - foreach - and make changes in the original list, which cannot be done directly).

You have deeply clone your list, that is actually generating new instances of objects for each element, as already suggested by bradbury9 (check here).

Community
  • 1
  • 1
Alexei - check Codidact
  • 22,016
  • 16
  • 145
  • 164