How do you break down your code?

  • (3 Pages)
  • +
  • 1
  • 2
  • 3

39 Replies - 1343 Views - Last Post: 07 February 2019 - 02:34 PM

#16 fearfulsc2   User is offline

  • D.I.C Head

Reputation: 15
  • View blog
  • Posts: 243
  • Joined: 25-May 16

Re: How do you break down your code?

Posted 06 February 2019 - 08:38 AM

So this is what I'm trying to break down.
I tried making it as generic as possible such as it can accept a list of objects of any type. But it's too big And I'm trying to find a way to break it down to cleaner blocks of code.

public async Task<(IList<DisparityHistory>, int)> CalculateDisparities<T, S>(IList<T> objectA, IList<S> objectB, IList<DisparityField> disparityFields, bool hasMultiple)
        {
            IList<DisparityHistory> disparityHistories = new List<DisparityHistory>();
            IList<DisparityHistory> tempDisparityHistories = new List<DisparityHistory>();
            int higherCount = 0;
            int lowerCount = 0;
            int disparities = 0;
            int tempDisparities = 0;
            var disparityHistory = new DisparityHistory();
            // If one or both are null, calculate disparities
            // and define the disparity history object and return
            if (objectA == null || objectB == null || objectA.Count == 0 || objectB.Count == 0)
            {
                if (objectA != null && (objectB == null || objectB.Count == 0))
                {
                    higherCount = objectA.Count();
                    for (int i = 0; i < higherCount; i++)
                    {
                        if (groupIndex == 0)
                            groupIndex++;
                        (tempDisparityHistories, tempDisparities) = await this.Compare(disparityFields, objectA[i], null, groupIndex);
                        disparities += tempDisparities;
                        foreach (var tempHistory in tempDisparityHistories)
                        {
                            disparityHistories.Add(tempHistory);
                        }
                        if (groupIndex > 1)
                            groupIndex++;
                        if (groupIndex == 1)
                            groupIndex++;
                    }

                }
                else if ((objectA == null || objectA.Count == 0) && objectB != null)
                {
                    if (groupIndex == 0)
                        groupIndex++;
                    higherCount = objectB.Count();
                    for (int i = 0; i < higherCount; i++)
                    {
                        //groupIndex++;
                        (tempDisparityHistories, tempDisparities) = await this.Compare(disparityFields, null, objectB[i], groupIndex);
                        disparities += tempDisparities;
                        foreach (var tempHistory in tempDisparityHistories)
                        {
                            disparityHistories.Add(tempHistory);
                        }
                        if (groupIndex > 1)
                            groupIndex++;
                        if (groupIndex == 1)
                            groupIndex++;
                    }
                }
                else
                {
                    disparityHistories = null;
                    disparities = 0;
                }
            }
            // If both are not null, compare both objects and calculate disparities
            else
            {
                bool isObjectAHigher = false;
                if (objectA.Count >= objectB.Count)
                {
                    higherCount = objectA.Count;
                    lowerCount = objectB.Count;
                    isObjectAHigher = true;
                }
                else
                {
                    higherCount = objectB.Count;
                    lowerCount = objectA.Count;
                }

                for (int i = 0; i < higherCount; i++)
                {
                    bool result = false;

                    if (lowerCount == 0)
                    {
                        if (objectA.Count == 0)
                        {
                            objectA = null;
                        }
                        if (objectB.Count == 0)
                        {
                            objectB = null;
                        }

                        (tempDisparityHistories, tempDisparities) = await this.CalculateDisparities(objectA, objectB, disparityFields, hasMultiple);
                        disparities += tempDisparities;
                        foreach (var tempHistory in tempDisparityHistories)
                        {
                            disparityHistories.Add(tempHistory);
                        }
                        break;
                    }

                    for (int j = 0; j < lowerCount; j++)
                    {
                        int fieldCount = 0;
                        bool foundUnique = false;

                        foreach (var field in disparityFields)
                        {
                            if (i < 0)
                            {
                                i = 0;
                            }
                            if (field.Compare)
                            {
                                if (isObjectAHigher)
                                {
                                   // this and the else statement below are exactly the same with the exception of the indexes such as objectB[j], objectB[i] (for the else below)
                                    (result, disparityHistory) = await this._compareHelper.Compare(objectB[j], objectA[i], field, groupIndex);
                                    disparityHistories.Add(disparityHistory);
                                }
                                else
                                {
                                    (result, disparityHistory) = await this._compareHelper.Compare(objectB[i], objectA[j], field, groupIndex);
                                    disparityHistories.Add(disparityHistory);
                                }
                                if (field.IsUnique && !result && hasMultiple)
                                {
                                    disparityHistories.Remove(disparityHistory);
                                    if (i == higherCount - 1)
                                    {
                                        var temp = objectB;
                                        temp = null;
                                        (tempDisparityHistories, tempDisparities) = await this.CalculateDisparities(objectA, temp, disparityFields, hasMultiple);
                                        foreach (var tempHistory in tempDisparityHistories)
                                        {
                                            disparityHistories.Add(tempHistory);
                                        }
                                        disparities += tempDisparities;

                                        (tempDisparityHistories, tempDisparities) = await this.CalculateDisparities(temp, objectB, disparityFields, hasMultiple);
                                        foreach (var tempHistory in tempDisparityHistories)
                                        {
                                            disparityHistories.Add(tempHistory);
                                        }
                                        disparities += tempDisparities;
                                    }
                                    break;
                                }
                                else if (field.IsUnique && result && hasMultiple)
                                {
                                    foundUnique = true;
                                }
                            }
                            // will still do the comparison but will not include it as part of the disparities
                            else
                            {
                                if (isObjectAHigher)
                                {
                                    (result, disparityHistory) = await this._compareHelper.Compare(objectB[j], objectA[i], field, groupIndex);
                                    disparityHistories.Add(disparityHistory);
                                }
                                else
                                {
                                    (result, disparityHistory) = await this._compareHelper.Compare(objectB[i], objectA[j], field, groupIndex);
                                    disparityHistories.Add(disparityHistory);
                                }
                                if(field.IsUnique && result && hasMultiple)
                                {
                                    foundUnique = true;
                                }
                            }

                            fieldCount++;
                            if (fieldCount == disparityFields.Count && foundUnique)
                            {
                                --higherCount;
                                --lowerCount;
                                groupIndex++;
                                if (isObjectAHigher)
                                {
                                    objectB.Remove(objectB[j]);
                                    objectA.Remove(objectA[i]);
                                }
                                else
                                {
                                    objectB.Remove(objectB[i]);
                                    objectA.Remove(objectA[j]);
                                }
                                i = -1;
                                j = -1;
                            }

                            if (!result)
                            {
                                if(field.Compare)
                                {
                                    disparities++;
                                }
                                if (objectB.Count == 0 || objectA.Count == 0)
                                {
                                    (tempDisparityHistories, tempDisparities) = await this.CalculateDisparities(objectA, objectB, disparityFields, hasMultiple);
                                    disparities += tempDisparities;
                                    foreach (var tempHistory in tempDisparityHistories)
                                    {
                                        disparityHistories.Add(tempHistory);
                                    }
                                    i = higherCount;
                                }
                            }
                        }
                    }
                }
            }
            return (disparityHistories, disparities);
        }

        // this is only called when there is no object to compare against, so disparities will always go up by 1. 
        private async Task<(IList<DisparityHistory>, int)> Compare(IList<DisparityField> disparityFields, object objectA, object objectB, int groupIndex)
        {
            IList<DisparityHistory> disparityHistories = new List<DisparityHistory>();
            bool result = false;
            var disparityHistory = new DisparityHistory();
            int disparities = 0;
            foreach (var field in disparityFields)
            {
                if (field.Compare)
                {
                    (result, disparityHistory) = await this._compareHelper.Compare(objectB, objectA, field, groupIndex);
                    disparityHistories.Add(disparityHistory);
                    disparities++;
                }
                // we still want the values but we will not include the result in the disparities
                // so even if there is a mismatch, it won't be part of the disparity calculation.
                else
                {
                    (result, disparityHistory) = await this._compareHelper.Compare(objectB, objectA, field, groupIndex);
                    disparityHistories.Add(disparityHistory);
                    continue;
                }
            }
            return (disparityHistories, disparities);
        }


This post has been edited by fearfulsc2: 06 February 2019 - 08:42 AM

Was This Post Helpful? 0
  • +
  • -

#17 modi123_1   User is offline

  • Suitor #2
  • member icon



Reputation: 14856
  • View blog
  • Posts: 59,272
  • Joined: 12-June 08

Re: How do you break down your code?

Posted 06 February 2019 - 09:03 AM

In a larger sense I would think if either list is null or has a count of zero you would just exit the function as there is nothing to proper compare. That should cleave off half of that.
Was This Post Helpful? 1
  • +
  • -

#18 andrewsw   User is online

  • Stealth IT
  • member icon

Reputation: 6737
  • View blog
  • Posts: 27,746
  • Joined: 12-December 12

Re: How do you break down your code?

Posted 06 February 2019 - 09:04 AM

Sorry to labour the point just once more but, in my opinion, if you are trying to build something that will accepts lists of any object type (without stemming from a common parent or interface(s)) then it will, of necessity, end up cumbersome and, more significantly, fragile.

I'll drop out, but good luck ;)
Was This Post Helpful? 0
  • +
  • -

#19 fearfulsc2   User is offline

  • D.I.C Head

Reputation: 15
  • View blog
  • Posts: 243
  • Joined: 25-May 16

Re: How do you break down your code?

Posted 06 February 2019 - 09:10 AM

View Postmodi123_1, on 06 February 2019 - 09:03 AM, said:

In a larger sense I would think if either list is null or has a count of zero you would just exit the function as there is nothing to proper compare. That should cleave off half of that.


I thought about that but I haven't yet found a way say this object has 7 properties and the other object is null or a size of 0.

Essentially, I still have to give back a json output that says it was compared and that each property in the non-null object has a data mismatch to the other.

View Postandrewsw, on 06 February 2019 - 09:04 AM, said:

Sorry to labour the point just once more but, in my opinion, if you are trying to build something that will accepts lists of any object type (without stemming from a common parent or interface(s)) then it will, of necessity, end up cumbersome and, more significantly, fragile.

I'll drop out, but good luck ;)/>



Thank you thank you.

If I can ask, how would you do that with the common parent or interface(s)?

I have a hard time conceptualizing that since everything I get is from the db. The fields object you see above was retrieved from the database by a certain group. And then those fields are the property names I have for the objects. So some objects can have 10 properties/fields while others can have 2 or 20, etc....

Is there a way for me to have a commonality between them all and have a parent/interface for that?
Was This Post Helpful? 0
  • +
  • -

#20 modi123_1   User is offline

  • Suitor #2
  • member icon



Reputation: 14856
  • View blog
  • Posts: 59,272
  • Joined: 12-June 08

Re: How do you break down your code?

Posted 06 February 2019 - 09:17 AM

@andrewsw - agreed.. a "do/take everything function" is never a good, or fun, way of going about things.

Quote

I thought about that but I haven't yet found a way say this object has 7 properties and the other object is null or a size of 0.

What do you mean? The input params are lists, right? Lists can be null or have a count of zero. Bingo bango. Check done.
Was This Post Helpful? 1
  • +
  • -

#21 andrewsw   User is online

  • Stealth IT
  • member icon

Reputation: 6737
  • View blog
  • Posts: 27,746
  • Joined: 12-December 12

Re: How do you break down your code?

Posted 06 February 2019 - 09:37 AM

Quote

If I can ask, how would you do that with the common parent or interface(s)?


That is too broad, so I must assume that you are not asking me how to write/define an interface or class inheritance (and/or abstract classes)?

This How to compare two objects (testing for equality) provides some useful information and examples.

Quote

I have a hard time conceptualizing that since everything I get is from the db. The fields object you see above was retrieved from the database by a certain group. And then those fields are the property names I have for the objects. So some objects can have 10 properties/fields while others can have 2 or 20, etc....

Is there a way for me to have a commonality between them all and have a parent/interface for that?


The data might come from a database, and consist of text, numbers, dates, etc., but each data item (or entity) must represent "something". If one represents a table and one represents a chair then they might have some commonality (perhaps the wood/material and perhaps having 4 legs). Obviously, it would be more appropriate to compare tables to tables.

If you are attempting to compare tables to bananas then I'd probably go out for lunch.
Was This Post Helpful? 0
  • +
  • -

#22 fearfulsc2   User is offline

  • D.I.C Head

Reputation: 15
  • View blog
  • Posts: 243
  • Joined: 25-May 16

Re: How do you break down your code?

Posted 06 February 2019 - 09:49 AM

That's essentially what the scenario is I believe.

We have a group table that has the overall amount of groups(like objects)

We have another fields table that has the fields we want for those groups. A group can have many fields while a field can have only one group.

We then have tables for those objects/groups.

Let's say Person is a group.
We get 2 Person-like objects called PersonA and PersonB.

PersonA and PersonB have the same property names and the same property types in their respective classes.

Now let's say there is an Animal group.

We get 2 Animal-like objects called AnimalA and AnimalB

They also have the same property names and the same property types are vastly different than PersonA and PersonB such as they have more properties and properties of different types.

Right now, if PersonA/B is to be compared to AnimalA/B, the program will break and exceptions will be thrown.

If PersonA is to be Compared to PersonB, the comparison will work regardless of if One or both of them are null or empty.

Same goes for AnimalA/B.

If one is null/empty, I still need to create a new object to display the result to the front-end.

Currently, it works but the code is too bulky and hard to maintain.

So I guess my question is, how should I break this down if each object I need to compare is vastly different than the other objects that are a part of different groups?

The only commonality that I can give them is that they all share the same overall globalID.

That's the only thing they all have in common.
Was This Post Helpful? 0
  • +
  • -

#23 modi123_1   User is offline

  • Suitor #2
  • member icon



Reputation: 14856
  • View blog
  • Posts: 59,272
  • Joined: 12-June 08

Re: How do you break down your code?

Posted 06 February 2019 - 09:53 AM

I mean it would help if folk know exactly what was being compared.. but at this point I would do it with a data type to other data type specific compare. There has to be some limit to this madness of compare everything to everything.. so if a new comparison of disparate data types comes up whip up a new function, check it in, and move on.
Was This Post Helpful? 1
  • +
  • -

#24 astonecipher   User is offline

  • Senior Systems Engineer
  • member icon

Reputation: 2766
  • View blog
  • Posts: 10,958
  • Joined: 03-December 12

Re: How do you break down your code?

Posted 06 February 2019 - 09:57 AM

Maybe a cleaner question is, what is the end goal, rather than how are you trying to go about it?


A class can compare itself to another of the same type. But a banana is hard to compare to the table.
Was This Post Helpful? 0
  • +
  • -

#25 modi123_1   User is offline

  • Suitor #2
  • member icon



Reputation: 14856
  • View blog
  • Posts: 59,272
  • Joined: 12-June 08

Re: How do you break down your code?

Posted 06 February 2019 - 09:59 AM

Quote

But a banana is hard to compare to the table.

Unless it's in a polar vortex then the banana can be as hard as a table. ;)
Was This Post Helpful? 0
  • +
  • -

#26 fearfulsc2   User is offline

  • D.I.C Head

Reputation: 15
  • View blog
  • Posts: 243
  • Joined: 25-May 16

Re: How do you break down your code?

Posted 06 February 2019 - 10:04 AM

@astonecipher

The end goal is to clean this up a bit.
As for what I need it to do, it goes like this:

We have a need to calculate all the differences between a package a client gives us and the package we have in our system and then show to our users how many differences there are and where they are.

These packages have many different sets of objects/data.

Let's say we have applications for a loan.

For that loan, we need the Persons Name, Address, Social, etc....
We also need a guarantor and their Name, Address, Social, etc.... -> can be a list of people being a guarantor
We also need a Summary such as term, monthly payment, interest rate, etc...

So in this example, we have the package from the customer with all that information and we have the package in our system with all that information.

We then need to compare each and every object and see how many differences there are based off of what the values are in the properties of those objects.

If they do not match, the number of mismatches go up by 1 for each mismatch in each property of each object.
Was This Post Helpful? 0
  • +
  • -

#27 astonecipher   User is offline

  • Senior Systems Engineer
  • member icon

Reputation: 2766
  • View blog
  • Posts: 10,958
  • Joined: 03-December 12

Re: How do you break down your code?

Posted 06 February 2019 - 10:12 AM

From that, a Person would be a parent of both the Guarantor and the Applicant. Then Loan could be a parent for the many types of loans.
A Package would be a combination of Applicant properties, Guarantor properties, and Loan Detail properties.
Following?


But, there is always going to be a difference between a Guarantor and the Applicant, correct? So, what types of mismatches do you need to look for? Contact info, Address, Loan terms, loan amounts? That type of thing?
Was This Post Helpful? 0
  • +
  • -

#28 fearfulsc2   User is offline

  • D.I.C Head

Reputation: 15
  • View blog
  • Posts: 243
  • Joined: 25-May 16

Re: How do you break down your code?

Posted 06 February 2019 - 11:09 AM

Yes, Guarantor will be different but we'll have a guarantor in our system and they will send us a guarantor. But we won't know for sure until we call the api to get that information.

And we don't actually get the package info. We get the information such as Guarantor and Applicant and so forth based off the ID. So when we get Guarantors from our customer and from our system, we would get all guarantors from customer and our system with that corresponding packageID.

We then compare. That's how it works today
Was This Post Helpful? 0
  • +
  • -

#29 Skydiver   User is online

  • Code herder
  • member icon

Reputation: 6767
  • View blog
  • Posts: 23,071
  • Joined: 05-May 12

Re: How do you break down your code?

Posted 06 February 2019 - 11:55 AM

I'm still trying to wrap my head around the first part.

So let's say I have:
List<A> listANull = null;
List<A> listAEmpty = new List<A>();
List<B> listBNull = null;
List<B> listBEmpty = new List<B>();



The comparison truth table looks like:
           | listBNull | listBEmpty
-----------+-----------+------------
listANull  |    same   | different
-----------+-----------+------------
listAEmpty | different |   same



Why is null different from an empty list?
Was This Post Helpful? 0
  • +
  • -

#30 fearfulsc2   User is offline

  • D.I.C Head

Reputation: 15
  • View blog
  • Posts: 243
  • Joined: 25-May 16

Re: How do you break down your code?

Posted 06 February 2019 - 12:03 PM

I'll try with a display

Applicant |objectAValue | objectBValue | DoesMatch
----------+-------------+--------------+-----------
FirstName |John         | Sohn         | NO
----------+-------------+--------------+-----------
LastName  | Doe         | Doe          | YES
----------+-------------+--------------+-----------


 Gurantor |objectAValue | objectBValue | DoesMatch
----------+-------------+--------------+-----------
FirstName |John         |              | NO
----------+-------------+--------------+-----------
LastName  | Doe         |              | NO
----------+-------------+--------------+-----------



 Gurantor |objectAValue | objectBValue | DoesMatch
----------+-------------+--------------+-----------
FirstName |             |  SALLY       | NO
----------+-------------+--------------+-----------
LastName  |             |   DOE        | NO
----------+-------------+--------------+-----------



In this case, we have 2 guarantor objects but nothing to compare it to. That's why I have the compare for null/empty objects because I still have to show that there is a data mismatch. In this case, the total mismatches come to 5
Was This Post Helpful? 0
  • +
  • -

  • (3 Pages)
  • +
  • 1
  • 2
  • 3