0

I have object:

var obj = new FileList
{
   FileInfo = new List<FileDiff>()
    {
      new ()
      {
         Name = "test1",
         Included = new Diff<int> {Added = new HashSet<int> {1, 2}},
         Excluded = new Diff<int> {Added = new HashSet<int> {1, 2}},
         Existing = new Diff<int> {Added = new HashSet<int> {1, 2, 3}}
  },
    new ()
     {
        Name = "test1",
        Included = new Diff<int> {Added = new HashSet<int> {3, 4, 5}},
        Excluded = new Diff<int> {Added = new HashSet<int> {11, 222}},
        Existing = new Diff<int> {Added = new HashSet<int>()}}
    },
   new ()
    {
       Name = "equal to test1",
       Included = new Diff<int> {Added = new HashSet<int> {1, 2}},
       Excluded = new Diff<int> {Added = new HashSet<int> {1, 2}},
       Existing = new Diff<int> {Added = new HashSet<int> {1, 2, 3}}
     },
   }
};

I want to transform this data to new model where name is not string but string[] and Included, Excluded and Existing are same for these string names:

var obj = new FileListV2
 {
   FileInfo = new List<FileDiff2>()
   {
    new ()
      {
        Names = new string[] {"test1", "equal to test1"},
        Included = new Diff<int> {Added = new HashSet<int> {1, 2}},
        Excluded = new Diff<int> {Added = new HashSet<int> {1, 2}},
        Existing = new Diff<int> {Added = new HashSet<int> {1, 2, 3}}
     },
    new ()
     {
       Names = new string[] {"test1"},
       Included = new Diff<int> {Added = new HashSet<int> {3, 4, 5}},
       Excluded = new Diff<int> {Added = new HashSet<int> {11, 222}},
       Existing = new Diff<int> {Added = new HashSet<int>()}}
     }
    }
};

I tried the following:

var obj2 = obj.FileList
    .GroupBy(f => new
    {
        f.Included,
        f.Excluded,
        f.Existing,
    })
    .Select(g => new FileListV2
    {
        Names = g.Select(f => f.Name).ToArray(),
        Included = g.Key.Included,
        Excluded = g.Key.Excluded,
        Existing = g.Key.Existing,
    });

However my values are not created I want them to. How should I compare those objects?

user122222
  • 2,179
  • 4
  • 35
  • 78
  • Would you mind fixing the code formatting? I'm on the cell phone and only seeing blank space for half of the code snippets. – Fildor Feb 12 '23 at 10:06

1 Answers1

0

From your code, obj is a FileList object but not an array (IEnumerable<T>). Thus, I doubt that your code works, but expect that you will get a compilation error for the FileList doesn't contains the GroupBy method.

Either

  • you need to use obj.FileList instead, or
  • assume that obj is the List<FileDiff> type.

The problem which .GroupBy not works as Included, Excluded, and Existing are (equality) compared by reference but not by value.

You have to implement the IEquatable<T> interface and override both GetHashCode and Equals methods. Therefore, when performing an equality check, both Diff<T> objects will be compared by the value.

One of the approaches to generating the hashcode for set/list, you may refer to @JonSkeet's answer on Good GetHashCode() override for List of Foo objects respecting the order.

public class Diff<T> : IEquatable<Diff<T>>
{
    public HashSet<T> Added { get; set; }
    
    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 19;
            foreach (var foo in Added)
            {
                hash = hash * 31 + foo.GetHashCode();
            }
            return hash;
        }
    }
     
    public override bool Equals(object obj)
    {
        return this.Equals(obj as Diff<T>);
    }

    public bool Equals(Diff<T> other)
    {
        if (other == null)
            return false;

        return this.Added.SetEquals(other.Added);
    }
}

public class FileDiff
{
    public string Name { get; set; }
    public Diff<int> Included { get; set; }
    public Diff<int> Excluded { get; set; }
    public Diff<int> Existing { get; set; }
}

public class FileDiff2
{
    public string[] Names { get; set; }
    public Diff<int> Included { get; set; }
    public Diff<int> Excluded { get; set; }
    public Diff<int> Existing { get; set; }
}

Console program

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
                    
public class Program
{
    public static void Main()
    {
        var obj = new List<FileDiff>()
                {
                    new FileDiff
                    {
                        Name = "test1",
                        Included = new Diff<int> {Added = new HashSet<int> {1, 2}},
                        Excluded = new Diff<int> {Added = new HashSet<int> {1, 2}},
                        Existing = new Diff<int> {Added = new HashSet<int> {1, 2, 3}}
                    },
                    new FileDiff
                    {
                        Name = "test1",
                        Included = new Diff<int> {Added = new HashSet<int> {3, 4, 5}},
                        Excluded = new Diff<int> {Added = new HashSet<int> {11, 222}},
                        Existing = new Diff<int> {Added = new HashSet<int>()}
                    },
                    new FileDiff
                    {
                        Name = "equal to test1",
                        Included = new Diff<int> {Added = new HashSet<int> {1, 2}},
                        Excluded = new Diff<int> {Added = new HashSet<int> {1, 2}},
                        Existing = new Diff<int> {Added = new HashSet<int> {1, 2, 3}}
                    },
                
            };
        
        var obj2 = obj
            .GroupBy(f => new
            {
                f.Included,
                f.Excluded,
                f.Existing,
            })
            .Select(g => new FileDiff2
            {
                Names = g.Select(f => f.Name).ToArray(),
                Included = g.Key.Included,
                Excluded = g.Key.Excluded,
                Existing = g.Key.Existing,
            })
            .ToList();
    
        
        Console.WriteLine(JsonSerializer.Serialize<List<FileDiff2>>((List<FileDiff2>)obj2, new JsonSerializerOptions { WriteIndented = true  }));
    }
}

Demo @ .NET Fiddle

Yong Shun
  • 35,286
  • 4
  • 24
  • 46
  • 2
    Please don't put the code for the answer on .NET Fiddle unless the full code is in the answer too. External links have a habit of breaking. Always consider if your answer is complete if the link were broken the moment you posted it. – Enigmativity Feb 12 '23 at 11:07
  • Hi @Enigmativity, thanks for the suggestion. Usually, I will post the code required for the solution in the answer post, while an external link to demonstrate the answer works. I will keep in mind on this. Thanks. – Yong Shun Feb 13 '23 at 03:04
  • 1
    We often ask for a [mcve] in the question. It doesn't change for the answer. Please put all of the code in the answer. – Enigmativity Feb 13 '23 at 03:40
  • Thank you! I still need to get more in depth with hashcode calculations as I'm not very familiar with the best practices of it (if you have any more resources on it I'd be grateful) , but managed to get the results I needed. Thanks! @YongShun – user122222 Feb 13 '23 at 08:18