0

I have text boxes and I get and set its input to the structure which is as follow.

public struct mappingData
{
    public string a;
    public string b;
    public int c;
}
mappingData mappingFileData;
public List<mappingData> mappingDatabase = new List<mappingData>();`

once the button is clicked I store it into List

private void btnAddMapData_Click(object sender, EventArgs e)
{
mappingFileData.a = addressPrefixMbDataType[cbMbDataType.SelectedIndex];
mappingFileData.b = addressPrefixMbValue[cbMbValue.SelectedIndex];
mappingFileData.c = Int32.Parse(tbAddress.Text);

// Add new entry to the linked list each time when 'btnAddMapData' is clicked 
mappingDatabase.Add(mappingFileData);
}

Now my database can be follows

a , x , 1

a , x , 2

b , x , 1

b , x , 2

but it should not be like as follows

a , x , 1

a , x , 1 > duplicate beacause already "1" is available previously

b , x , 2

b , x , 2 > duplicate beacause already "2" is available previously

b , x , 1 > not a duplicate because 1st parameter is different that is 'b' so "a" and "b" both can hold 1 since both are different and but if there is two "a" in the list then there should be only one "1".

Someone, please suggest me an idea

Community
  • 1
  • 1
kaviarasan
  • 115
  • 2
  • 13
  • What are the exact rules that two items are considered equal (duplicate)? I.e. could you provide an implementaion of a method `public bool Equals(mappingData a, mappingData b)` that would return `true` if `a` and `b` are duplicates and `false` otherwise? – Corak Aug 07 '17 at 11:47
  • 1
    I would recommend that you change the struct into a class. Then you can implement the IEquatable> Interface. After then you should be able to use mappingDatabase.Contains() – Noren Aug 07 '17 at 11:50

3 Answers3

2

If you want a surefire way to check for duplicates, you'll have to first modify your struct to override the == operator and the associated methods:

public struct mappingData
{
    public string mbDataType;
    public string mbValue;
    public string daliAddrType;
    public int mbAddress;
    public string daliCmdNo;
    public int daliDevId;

    public override bool Equals(Object obj)
    {
        return obj is mappingData && this == (mappingData)obj;
    }

    public override int GetHashCode()
    {
        return (mbDataType.GetHashCode() + mbValue.GetHashCode() + daliAddrType.GetHashCode() + daliCmdNo.GetHashCode()) * mbAddress * 807403 * daliDevId;
    }

    public static bool operator ==(mappingData x, mappingData y)
    {
        return x.mbDataType == y.mbDataType && x.mbValue == y.mbValue && x.daliAddrType == y.daliAddrType && x.mbAddress == y.mbAddress && x.daliCmdNo == y.daliCmdNo && x.daliDevId == y.daliDevId;
    }

    public static bool operator !=(mappingData x, mappingData y)
    {
        return !(x == y);
    }
}

Now, you can use LINQ or similar methods and compare identical instances of mappingData:

if (!mappingDatabase.Contains(mappingFileData))
{
    mappingDatabase.Add(mappingFileData);
}

EDIT:

If you only want to check for the same mbAddress and mbDataType, then you don't need to modify your struct at all. You can do this right away:

if (!mappingDatabase.Any(m => m.mbAddress == mappingFileData.mbAddress && m.mbDataType == mappingFileData.mbDataType))
{
    mappingDatabase.Add(mappingFileData);
}
stelioslogothetis
  • 9,371
  • 3
  • 28
  • 53
  • am confused, can please update the code for this structure public struct mappingData { public string mbDataType; public string mbValue; public string daliAddrType; public int mbAddress; public string daliCmdNo; public Int32 daliDevId; } – kaviarasan Aug 07 '17 at 12:03
  • Using XOR for hashcode calcs can cause more collisions that one might expect. Better to perform unchecked multiplications with a prime: https://stackoverflow.com/questions/38280843/how-to-pick-prime-numbers-to-calculate-the-hash-code – spender Aug 07 '17 at 12:04
  • @kaviarasan Check out the edit. It is actually really simple. You use the hash codes for each field in the `GetHashCode()` method, and you compare all fields of `x` to all fields of `y` in the `==` override. – stelioslogothetis Aug 07 '17 at 12:09
  • I don't know whether u go my question or not, at I never used hash codes so it's all over confusing me. I will explain u my question again here for u. – kaviarasan Aug 07 '17 at 12:14
  • @kaviarasan Your question was how to check for duplicates. The answer is add these methods to your struct, and then you can use `Contains`. – stelioslogothetis Aug 07 '17 at 12:15
  • There is two struct member one is mbDataType and another one is mbAddress. Now member mbDataType will have any of the four values lets say a,b,c,d and now there should not be any duplication of mbAddress w.r.t to a,b,c,d I mean a,b,c,d can have integer 1 each but "a" cannot have two times integer 1 in similar way even b,c,d cannot have integer 1 twice. In List how do I find whether that a with integer 1 has already present or not? – kaviarasan Aug 07 '17 at 12:22
  • Your code works, but it checks duplication of all the struct member but for me it should check duplication of "mbAddress" alone? just one more step to accept this answer, please edit the code. – kaviarasan Aug 07 '17 at 12:32
  • @kaviarasan You should have made that clear in your question. Check the edit. – stelioslogothetis Aug 07 '17 at 12:35
  • @stybl, `struct`s provide adequate implementation for `Equals` which compares fields. that enough for Contains to work properly – ASh Aug 07 '17 at 12:41
  • I mentioned in my edit above mbAddress should check w.r.t to mbDataType. I meant that mbDataType has four values a,b,c,d but now there should not be any duplication of mbAddress w.r.t to a,b,c,d I mean a,b,c,d can have integer 1 each but "a" cannot have two times integer 1 in similar way even b,c,d cannot have integer 1 twice. In List how do I find whether that a with integer 1 has already present or not? – kaviarasan Aug 07 '17 at 12:43
  • @ASh AFAIK the default implementation only does that from .NET 4.5 on. OP didn't mention a version. – stelioslogothetis Aug 07 '17 at 12:43
  • @kaviarasan Let me make sure I have this correctly. You want no instances with the same `mbAddress` to have the same `mbDataType` as each other? – stelioslogothetis Aug 07 '17 at 12:46
  • Yes your right, but it can be like same mbAddress to have the different mbDataType but not same mbdataType. – kaviarasan Aug 07 '17 at 12:49
  • Wow, this simple and it works like a charm. Thanks for enriching my knowledge with hash code. – kaviarasan Aug 07 '17 at 13:13
2

If you use a struct the default implementation takes all fields into consideration to generate the resulting hash code. So by simply putting your struct into a HashSet<> should solve your problem:

using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        var items = Enumerable.Range(1, 100)
                              .Select(value => value % 10)
                              .Select(value => new mappingData{ a = "a" + value, b = "b" + value, c = value });
        var hashSet = new HashSet<mappingData>(items);

        // Outputs only first ten elements
        foreach(var item in hashSet)
        {
            Console.WriteLine(item);
        }

    }

    public struct mappingData
    {
        public string a;
        public string b;
        public int c;

        public override string ToString()
        {
            return $"{a} {b} {c}";
        }
    }
}
Oliver
  • 43,366
  • 8
  • 94
  • 151
1

List has several extension methods which can help you find data in the list. In your case I would suggest to use the Count method. It should also work on a struct.

int found = mappingDatabase.Count(delegate (mappingData obj) { return obj.a.Equals("a") && obj.b.Equals("x"); });

You can then set your own rules for searching and determining if it is a duplicate or not.

Don't forget to check that mappingDatabase is not null before calling Count.

jason.kaisersmith
  • 8,712
  • 3
  • 29
  • 51