-1

I have a List of a class object(obj1), and that class contains another List of a different class object(obj2). Below is my code:

public List<Class1> Obj1{ get; set; }

 public class Class1
    {
        [DataMember]
        public int Class1Id { get; set; }
        [DataMember]
        public string Class1Desc { get; set; }
        [DataMember]
        public List<Class2> obj2{ get; set; }
    }

public class Class2
    {
        [DataMember]
        public int Class2Id { get; set; }
        [DataMember]
        public string Class2Desc { get; set; }
    }

Now, I need to populate the variables making sure that I don't get duplicate values (i.e. the combination of Class1Id and Class2Id should be unique).

I don't want to use loops. How can I achieve this?

eye_am_groot
  • 682
  • 6
  • 19
Amit Verma
  • 29
  • 1
  • 1
  • 6
  • you could individually set them with some sort of method that you make in Class1 – dave Jun 22 '18 at 12:05
  • 1
    You can use a `Hashset` ? – CodeNotFound Jun 22 '18 at 12:06
  • 1
    "Now, I need to populate the variables" - which variables? The ones on the class? If so what is your source of data? Or are you populating other variables from your Obj1 list in which case what variables are you wanting to populate and with what data? – Chris Jun 22 '18 at 12:07
  • Here is one liner: *var result = Obj1.SelectMany(x=> x.obj2.Select(y=> new {x,y})).GroupBy(t=> new {t.x.Class1Id, t.y.Class2Id}).Select(x=> x.First()).ToList();* – eocron Jun 22 '18 at 12:08
  • 1
    Can you provide an example? Do you think the title is appropriate? Do you think that regex is relevant? – Tim Schmelter Jun 22 '18 at 12:08
  • So if `Class1Id = 1` and any of the objects in `List obj2` have a `Class2Id = 1`, then this `Class1`-instance is a duplicate? Or if there is a second `Class1`-instance` with `Class1Id=1` (or any of the objects in `List obj2` have a `Class2Id=1`), then the second instance is a duplicate? The question is very, very unclear. What means _"combination of Class1Id and Class2Id should be unique"_? The `Class2Id` is in a list, so what is the combination of a single `int` and a `List`? – Tim Schmelter Jun 22 '18 at 12:18
  • @CodeNotFound: If you think that is a solution you should give an answer on how to use it. As it is you can't just use a `Hashset` because `Class2` currently has the default implementation of `GetHashCode` which will not do what the OP wants (I believe). – Chris Jun 22 '18 at 12:26
  • @Chris I'm waiting the answer of the OP :) Even if he says yes, I will point him to this [post](https://stackoverflow.com/questions/18081595/c-sharp-defining-hashset-with-custom-key). – CodeNotFound Jun 22 '18 at 12:31
  • By variables I mean the class members of Class1 and Class2. By unique I mean that if Class1Id=1 and Class2Id=1, it is unique, considering that there is no such combination in ListObj1. I hope this help you guys understand my issue. – Amit Verma Jun 22 '18 at 12:38
  • @AmitVerma: I now know that you want to populate the class members of Class1 and Class2 - I still don't know what source you want to use to get the data? Where do the values for Class1Id come from? – Chris Jun 22 '18 at 12:49

1 Answers1

0

Use IEquatable then use Distinct():

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace ConsoleApplication52
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Class1> Obj1 = new List<Class1> {
                new Class1() { Class1Desc = "A", Class1Id = 1, obj2 = new List<Class2>() { new Class2() { Class2Id = 100, Class2Desc= "M"}}},
                new Class1() { Class1Desc = "B", Class1Id = 1, obj2 = new List<Class2>() { new Class2() { Class2Id = 100, Class2Desc= "M"}}},
                new Class1() { Class1Desc = "A", Class1Id = 1, obj2 = new List<Class2>() { new Class2() { Class2Id = 100, Class2Desc= "M"}}},
                new Class1() { Class1Desc = "A", Class1Id = 1, obj2 = new List<Class2>() { new Class2() { Class2Id = 200, Class2Desc= "M"}}}
            };

            List<Class1> distinctClass1 = Obj1.Distinct().ToList();
        }
    }
    public class Class1 : IEquatable<Class1>
    {
        public int Class1Id { get; set; }
        public string Class1Desc { get; set; }
        public List<Class2> obj2 { get; set; }

        public Boolean Equals(Class1 other)
        {

            if (other == null) return false;
            if ((this.Class1Id == other.Class1Id) && (this.Class1Desc == other.Class1Desc) && (this.obj2.OrderBy(x => x).SequenceEqual(other.obj2.OrderBy(x => x))))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        public override int GetHashCode()
        {
            return (this.Class1Id.ToString() + "^" + this.Class1Desc + string.Join("^", obj2.Select(x => x.GetHashCodeStr()))).GetHashCode();
        }

    }

    public class Class2 : IEquatable<Class2> , IComparer<Class2>
    {
        public int Class2Id { get; set; }
        public string Class2Desc { get; set; }

        public Boolean Equals(Class2 other)
        {
            if(other == null) return false;
            if ((this.Class2Id == other.Class2Id) && (this.Class2Desc == other.Class2Desc))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        public int Compare(Class2 x, Class2 y)
        {
            int results = 0;
            results = x.Class2Id.CompareTo(y.Class2Id);
            if (results == 0)
            {
                results = x.Class2Desc.CompareTo(y.Class2Desc);
            }
            return results;
        }
        public override int GetHashCode()
        {
            return (this.Class2Id.ToString() + "^" + this.Class2Desc).GetHashCode();
        }
        public string GetHashCodeStr()
        {
            return this.Class2Id.ToString() + "^" + this.Class2Desc;
        }

    }
}
jdweng
  • 33,250
  • 2
  • 15
  • 20
  • I think you might need to implement more than just `IEquatable` to get that `Distinct` to work - I believe `GetHashCode` will be needed too. `Distinct()` will create a `EqualityComparer.Default` which relies on `GetHashCode` I believe. At least your code doesn't work for me and I think that is the reason why. – Chris Jun 22 '18 at 12:23
  • How does this take care of _"making sure that I don't get duplicate values (i.e. the combination of **Class1Id** and **Class2Id** should be unique)"_? I guess that one `Class1` instance is a duplicate of another `Class1` instance if both have intersecting `new[]{Class1Id}.Union(obj2.Select(x=>x.Class2Id))` integers. But maybe all integers must be the same and not only one. – Tim Schmelter Jun 22 '18 at 12:25
  • I was surprised that code compiled without error not using GetHashCode(). You really don't need the hash code and you can put into the hash return 0 and it will work. The IEquatable calls GetHashCode to first check if items are equal and then calls the Equal method when hash are not equal. If you are just doing compares A (and not < >) why create a hash that isn't needed. I believe it is using the standard List<> GetHashCode as the default. Normally you use override with GetHashCode(). – jdweng Jun 22 '18 at 12:27
  • @Tim Schmelter : The IEquatable handles the duplicates. My code assumes that all objects in both Class one and class two have to be the same. The classes are list objects so the standard List Equal is used as the base class for comparison. – jdweng Jun 22 '18 at 12:34
  • @jdweng: https://www.ideone.com/XRv0dr is a cut down version of your code (removing class 2). It doesn't seem to detect the duplicate objects added to the list (should have 10 distinct objects and also the Console.WriteLine in Equals never seems to get called). (I don't think I've screwed anything up in cutting down your code). – Chris Jun 22 '18 at 12:41
  • Looks like `Distinct` creates a `Set` which uses the hashcode first and only then the equals method - https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,71eda981b7574f10 – Chris Jun 22 '18 at 12:47
  • I finally got it to run correctly using SequenceEqual – jdweng Jun 22 '18 at 14:25