1

So, C# has a wonderful feature where you can add actual variables to lists, but that is unhelpful for me right now as I want the value of said variable.

public List<List<float?>> distMatrix = new List<List<float?>>();
public List<List<float>> routeMatrix = new List<List<float>>();
public List<List<List<float?>>> distMatrixHistory = new List<List<List<float?>>();
public List<List<List<float>>> routeMatrixHistory = new List<List<List<float>>();

This is where I am defining my variables.

distMatrixHistory.Add(distMatrix);  
routeMatrixHistory.Add(routeMatrix);

And this is the piece of code I have that adds those matrices to the matrix history list. The issue is that I loop and change the value of these matrices, but I don't want the value of the elements in the matrixhistory lists to change too.

I know that, theoretically, I can just do this manually. I know that I can probably program a small function that would cycle through and add each value separately. But this seems like something that c# should have inbuilt functions (or libraries) to deal with, even if I have not found anything when looking into it.

Side note: If anyone wants a bit more context, this is a small program that runs Floyd's Algorithm, so I cycle every step and change my distance and my route matrix, and my little winforms app should theoretically be able to display any step requested.

Maytham Fahmi
  • 31,138
  • 14
  • 118
  • 137
  • 1
    So essentially you just want a _copy_ of `distMatrix` and `routeMatrix` to be added to their histories? – Sweeper Nov 14 '19 at 10:45
  • The term is "deep copy". Since you're working with value types (`float`), an easy way to deep copy a simple list is: `var listB = new List(listA)`. But since a List itself is a reference type, you can't simply do `var listListB = new List>(listListA)`. You probably have to do something like `var listListB = new List>(listListA.Count); foreach(var listA in listListA) { listListB.Add(new List(listA)); }` -- and then add _that_ `listListB` to the archive. – Corak Nov 14 '19 at 11:07

1 Answers1

2

Create a copy using the List<T>(IEnumerable<T>) constructor:

List<List<float>> copy = routeMatrix.Select(list => new List<float>(list)).ToList();
routeMatrixHistory.Add(copy);

Then you can safely change values in your routeMatrix without affecting the history.

You could wrap this in an extension method if it needs to be reused:

static class Extensions
{
    static List<List<T>> Copy<T>(this List<List<T>> list)
    {
        return list.Select(l => new List<T>(l)).ToList();
    }
}

Example usage:

distMatrixHistory.Add(distMatrix.Copy());
routeMatrixHistory.Add(routeMatrix.Copy());
Johnathan Barclay
  • 18,599
  • 1
  • 22
  • 35
  • So, this seems like a fairly helpful answer, and this is something I WILL need to reuse a fair few times (aka in a loop) but I'm not sure how to add the extension method. I tried copying it but Visual Studio doesn't recognise it. The only difference I can think of is that I am not using static at all (I created a new instance of my class at the start because I don't know how to work with static much.) I tried adding it as it is, and I tried adding it as a public but it didn't seem to be recognised by Visual studio. Any help? I am getting the error – Nur Luski Levi Nov 15 '19 at 10:44
  • @NurLuskiLevi extension methods need to be defined in a static class, so you will probably need to create a new class. I'll update my answer to clarify. – Johnathan Barclay Nov 15 '19 at 11:00
  • Thank you very much, that solved my error, but for some reason I still can't call upon the Copy method like you did in the example usage. Would everything need to be in a static class? – Nur Luski Levi Nov 15 '19 at 11:08
  • You can also use a serialisation based deep copy which was nicely answered in this post [here](https://stackoverflow.com/questions/129389/how-do-you-do-a-deep-copy-of-an-object-in-net-c-specifically). – 3DPrintScanner Nov 15 '19 at 11:14
  • @NurLuskiLevi no, extension methods can be used anywhere. Is your static extensions class in the same namespace? If not, have you added the relevant using statement? Have you given the extension method the correct access modifier to be used in your other code e.g. `public` / `internal`? I didn't add access modifiers to the example as that is an implementation detail that you would need to decide. – Johnathan Barclay Nov 15 '19 at 12:50
  • @NurLuskiLevi just to add, you would need to declare `Copy` as either `public` or `internal`, as by default it would be `private`. – Johnathan Barclay Nov 15 '19 at 12:55