0

I got the following code

List<RRProcess> noDuplicates = pSorted
    .GroupBy(i => i.pID)
    .Select(group => group.First())
    .ToList();

The problem is, that if I change anything in the noDuplicates, it will change it in the pSorted as well. I've read all the posts about how the create a new list, but still cant figure it out in my case, how do I have to do it.

So the question is, how do I create a new list, from the elements of pSorted, without duplicating the objects which have the same pID?

thanks

Masoud Andalibi
  • 3,168
  • 5
  • 18
  • 44
Gyula Soós
  • 467
  • 1
  • 9
  • 23
  • `RRProcess` is a class, so a reference type. That's why you change the items in both collecions. You need to create new instances, either by creating a copy-constructor or by assigning all properties manually. – Tim Schmelter Jan 03 '17 at 11:50
  • You are creating a new list when use `ToList()`, I think you want create "copy" of items in the list, isn't it? – Fabio Jan 03 '17 at 11:50
  • So you want to be able to do something like `noDuplicates[0].Property = 5;` and the original object in pSorted should not reflect that change? If so then you are going to have to clone the objects in some way. As it stands it is the same object in both lists so the only way to get what you want is to have different objects in each list. – Chris Jan 03 '17 at 11:50
  • you question is a little unclear do you want a New List of New objects or a New List, the first means that if you edit an object from List 1 the same object in List 2 retains its original value, the second changing the value of the object will change it in both collections – MikeT Jan 03 '17 at 12:01

2 Answers2

6

You'll need to create new objects if you want to prevent this. There are multiple ways, e.g. use ICloneable, or create new objects yourself.

If your class implements ICloneable:

List<RRProcess> noDuplicates = pSorted
    .GroupBy(i => i.pID)
    .Select(group => (RRProcess) group.First().Clone())
    .ToList();

Or if it has a constructor that allows making a copy from an original:

List<RRProcess> noDuplicates = pSorted
    .GroupBy(i => i.pID)
    .Select(group => new RRProcess(group.First()))
    .ToList();

Or using a parameterless constructor + object initializer:

List<RRProcess> noDuplicates = pSorted
    .GroupBy(i => i.pID)
    .Select(group => group.First())
    .Select(x => new RRProcess { pID = x.pID /* etc for other properties */ } )
    .ToList();

Note that creating a copy - no matter how - can be tricky, e.g. if the original has a collection, you may find that the copied object needs to get a copy of that collection, and not just a new reference to that same old collection. This is called deep cloning. Both can work, it depends on if you need this or not.

Peter B
  • 22,460
  • 5
  • 32
  • 69
3

It cannot be done directly in LINQ, it requires some additional code from your side.

If your objects (In this case RRProcess.) doesn't have any members that are objects, then you can implement a clone method for your object like below:

    public RRProcess Clone()
    {
        return this.MemberwiseClone();
    }

I shall note that MemberwiseClone will only produce a shallow clone, hence why it will not clone objects.

In cases where RRProcess implements objects and you need to clone those too then you have to perform a deep clone.

See this answer: https://stackoverflow.com/a/129395/2026276

You can use the above to implement ICloneable see: https://msdn.microsoft.com/en-us/library/system.icloneable(v=vs.110).aspx

However I advice you in your case to implement it without, because Clone() from ICloneable only returns an object which will require further casting from your side and it may not be worth it in your case.

What you can then do is this:

List<RRProcess> noDuplicates = pSorted
    .GroupBy(i => i.pID)
    .Select(group => group.First().Clone())
    .ToList();

If you implement ICloneable

List<RRProcess> noDuplicates = pSorted
    .GroupBy(i => i.pID)
    .Select(group => (RRProcess)group.First().Clone())
    .ToList();
Community
  • 1
  • 1
Bauss
  • 2,767
  • 24
  • 28