CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 2 of 2
  1. #1
    Join Date
    Jun 2016
    Location
    Columbus, Ohio, USA
    Posts
    12

    [RESOLVED] List<T>.Except() not working for me

    In a nutshell, I have two generic lists of objects that I am using the .Except() extended method to return a list of exceptions into a new list. I remember getting this to work when I first researched it, but now that I am plugging it into the rest of the code, it returns the entire list instead of the exceptions.

    The list is of these records:
    Code:
    using System;
    using System.Configuration;         // ADD REFERENCE: System.Configuration (StringValidator)
    
    namespace OHS_RCIS.Report.OB_Adv
    {
        public class DenialRecord
        {
            private string inv_no;
            private string cur_bal;
            private string vendor;
            private string adm_dt;
            private string dschrg_dt;
            private string crt_dt;
            private string visit_ID;
    
            // Exposed constructor
            public DenialRecord
            (
                string Inv_No,
                string Cur_Bal,
                string Vendor,
                string Adm_Dt,
                string Dschrg_Dt,
                string Crt_Dt,
                string Visit_ID
            )
            {
                this.inv_no = FieldValidate(Inv_No);
                this.cur_bal = FieldValidate(Cur_Bal);
                this.vendor = FieldValidate(Vendor);
                this.adm_dt = FieldValidate(Adm_Dt);
                this.dschrg_dt = FieldValidate(Dschrg_Dt);
                this.crt_dt = FieldValidate(Crt_Dt);
                this.visit_ID = FieldValidate(Visit_ID);
            }
    
            // Properties used by the recon files as fields
            public string Inv_No { get { return inv_no; } set { inv_no = FieldValidate(Inv_No); } }             // always a string of 7-4 - null if Mansfield/Marion
            public string Cur_Bal { get { return cur_bal; } set { cur_bal = FieldValidate(Cur_Bal); } }         // currency in spreadsheet
            public string Vendor { get { return vendor; } set { vendor = FieldValidate(Vendor); } }             // always a string
            public string Adm_Dt { get { return adm_dt; } set { adm_dt = FieldValidate(Adm_Dt); } }             // a date in spreadsheet
            public string Dschrg_Dt { get { return dschrg_dt; } set { dschrg_dt = FieldValidate(Dschrg_Dt); } } // a date in spreadsheet
            public string Crt_Dt { get { return dschrg_dt; } set { dschrg_dt = FieldValidate(Crt_Dt); } }       // a date in spreadsheet
            public string Visit_ID { get { return visit_ID; } set { visit_ID = FieldValidate(Visit_ID); } }     // a number in spreadsheet - null if O'Bleness
    
            // Current AdviCare files come in with the balance field containing $ - invoice has a hyphen - headers contain underscores -  
            // dates have a forward slash. No other special characters should be legal.
            private string FieldValidate(string field)
            {
                string testVal = field;
                StringValidator strValidator = new StringValidator(1, 40, "!@#%^&*()+={}[]|?:;");
    
                try
                {
                    strValidator.Validate(field);
                }
                catch (ArgumentException e)
                {
                    Console.WriteLine("Error: {0}", e.ToString());
                }
                return field;
            }
    
            // Built-in comparer for list to list exceptions finding. Uses defined field in each record to compare.
            public DenialRecord Except(DenialRecord other)
            {
                if (this.inv_no != other.inv_no)
                {
                    return this;
                }
                else
                {
                    return null;
                }
            }
        }
    }
    The declaration of the lists is as follows:
    Code:
                // Declare lists to hold active inventory and to hold exceptions
                List<DenialRecord> hospList = new List<DenialRecord>();
                List<DenialRecord> vendList = new List<DenialRecord>();
                List<DenialRecord> hospExcpt = new List<DenialRecord>();
                List<DenialRecord> vendExcpt = new List<DenialRecord>();
    The actual call to the Except method is here:
    Code:
                // Compare the lists each way for denials not in the other source
                hospExcpt = hospList.Except(vendList).ToList();
                vendExcpt = vendList.Except(hospList).ToList();
    The class that builds the list is here:
    Code:
            // Load csv to List<T>
            public List<DenialRecord> CsvToList(out int returnValue)
            {
                //int errorCode = 0;
                using (TextFieldParser csvParser = new TextFieldParser(this.fullPath))
                {
                    csvParser.TextFieldType             = FieldType.Delimited;
                    csvParser.SetDelimiters(",");
                    csvParser.HasFieldsEnclosedInQuotes = true;
                    csvParser.TrimWhiteSpace            = true;
                    returnValue                         = Error.ERROR_SUCCESS;
                    while (!csvParser.EndOfData)
                    {
                        try
                        {
                            string[] field = csvParser.ReadFields();
                            if (field.Length == columnCount)
                            {
                                DenialRecord dr = new DenialRecord(field[0], field[1], field[2], field[3], field[4], field[5], field[6]);
                                inputList.Add(dr);
                            }
                        }
                        catch (Exception e)
                        {
                            switch(e.HResult)
                            {
                                case 2:
                                    returnValue = Error.ERROR_FILE_NOT_FOUND;
                                    break;
                                case 3:
                                    returnValue = Error.ERROR_PATH_NOT_FOUND;
                                    break;
                                case 5:
                                    returnValue = Error.ERROR_ACCESS_DENIED;
                                    break;
                                case 11:
                                    returnValue = Error.ERROR_FORMAT;
                                    break;
                                case 167:
                                    returnValue = Error.ERROR_MALFORMED_LINE;
                                    break;
                                case unchecked((int)0x80131502):
                                    returnValue = Error.ERROR_ARGUMENT_OUT_OF_RANGE;
                                    break;
                            }
                            DenialRecord dr = new DenialRecord("bad data", "bad data", "bad data", "bad data", "bad data", "bad data", "bad data");
                            inputList.Add(dr);
                        }
                    }
                }
                return inputList;
            }
        }
    }
    The field each list is using for the comparison is a string. So far, I have not seen a reason in looking at the List<T> class, its methods or the classes it inherits from. There has got to be a reason I am just not seeing. Has anyone thought of what I could have overlooked?

    EDIT: I found the solution here on CodeGuru. Mutant_Fruit explained it much more clearly than the places I had been looking. Essentially, even though you roll your own .Except() method in your class, when comparing objects or non-numbers, you have to build a hash of the field and override the Equals() function to do the correct compare required by the Exclude() function. Below is the working code:
    Code:
                    // Built-in comparer for list to list exceptions finding. Uses defined field in each record to compare.
            public DenialRecord Except(DenialRecord other)
            {
                if (this.inv_no != other.inv_no)
                {
                    return this;
                }
                else
                {
                    return null;
                }
            }
    
            // Except() requires overriding the Equals() and GetHashCode() to know how to compare
            public override bool Equals(object other)
            {
                if (other is DenialRecord)
                    return ((DenialRecord)other).inv_no == inv_no;
                else
                    return ((DenialRecord)other).inv_no == inv_no;
            }
    
            public override int GetHashCode()
            {
                return inv_no.GetHashCode();
            }
    Last edited by Jim Snyder; September 22nd, 2016 at 02:48 PM. Reason: Found solution
    .NET Framework Version 4.5.50938; Visual Studio Professional 2013 Version 12.0.21005.1 REL
    "Having power is nice, having a lot of power is very nice, having too much power is just about right!"

  2. #2
    Arjay's Avatar
    Arjay is offline Moderator / EX MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    13,490

    Re: List<T>.Except() not working for me

    Jim, took the liberty of marking the thread resolved since you indicated you found the solution.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured