Set operations (complement and difference)

208 views Asked by At

How can I make set complement and set difference in C# without using any collections and Linq?

We have two arrays:

int [] arr1 = new int { 1, 2, 3, 4};
int[] arr2 = new int {3,4,5,6,7,8};

Complement must be: arr3 {5,6,7,8} and the difference must be: arr4 {1,2}.

I've tried adding one set to another and then finding duplicates, but couldn't make it.

int numDups = 0, prevIndex = 0;

for (int i = 0; i < array.Length; i++)
{
    bool foundDup = false;
    for (int j = 0; j < i; j++)
    {
        if (array[i] == array[j])
        {
            foundDup = true;
            numDups++; // Increment means Count for Duplicate found in array.
            break;
        }                    
    }

    if (foundDup == false)
    {
        array[prevIndex] = array[i];
        prevIndex++;
    }
}

// Just Duplicate records replce by zero.
for (int k = 1; k <= numDups; k++)
{               
    array[array.Length - k] = '\0';             
}
3

There are 3 answers

2
Gusman On BEST ANSWER

You can create two lists, one for complement and other for difference, iterate array A and check which are contained in B and which not and vice-versa, iterate B and check which ones exists in A.

UPDATE: removed lists, used only arrays and no LINQ.

int[] arr1 = new int[]{ 1,2,3,4 };
int[] arr2 = new int[]{ 3,4,5,6,7,8 };

//We allocate the max possible size for each array, just for sanity
int[] arr3 = new int[arr1.Length + arr2.Length];
int[] arr4 = new int[arr1.Length + arr2.Length];

int difIndex = 0;
int compIndex = 0;

//Compute difference 
foreach(int i in arr1)
{
    bool found = false;
    foreach(int i2 in arr2)
    {
        if(i == i2)
        {
            found = true;
            break;
        }
    }

    if(!found)
        arr4[difIndex++] = i;
}

//Compute complement
foreach(int i in arr2)
{
    bool found = false;
    foreach(int i2 in arr1)
    {
        if(i == i2)
        {
            found = true;
            break;
        }
    }

    if(!found)
        arr3[compIndex++] = i;
}

//Remove unused items from array
Array.Resize(ref arr3, compIndex);
Array.Resize(ref arr4, difIndex);
0
lucasreta On

Given that premise, we could create the function getComplement like so:

int[][] getComplement(int[] arr1, int[] arr2) {
    
    int[] complement = {};
    int[] difference = {};

    for (int i = 0; i < arr1.Length; i++)
    {
        bool isDupe = false;
        for (int j = 0; j < arr2.Length; j++) {
            if (arr1[i] == arr2[j] && !isDupe) {
                Array.Resize(ref complement, complement.Length + 1);
                complement[complement.GetUpperBound(0)] = arr2[j];
                isDupe = true;
            }
        }
        if (!isDupe) {
            Array.Resize(ref difference, difference.Length + 1);
            difference[difference.GetUpperBound(0)] = arr1[i];
        }
    }
    
    return new[] { complement, difference };
}

and then apply it upon our 2 existing arrays to get the desired results:

int [] arr1 = new int[] { 1, 2, 3, 4 };
int[] arr2 = new int[] { 3, 4, 5, 6, 7, 8 };
int[][] complementArr = getComplement(arr1, arr2);
int[][] differenceArr = getComplement(arr2, complementArr[0]);
int[] arr3 = differenceArr[1];
int[] arr4 = complementArr[1];

You can see a working demo here.

0
Abion47 On

The difference between collections A and B are all elements in A that are not in B. The compliment between those collections are all elements in B that are not in A. These are mirror definitions, so you really only need to write a method for difference and then have the compliment method call the difference method with the input parameters reversed.

(Well, strictly speaking, the compliment is all elements anywhere that are not in A, but that distinction is irrelevant here.)

// Get an array of all elements in b that are not in a
// This is identical to calling GetDifference with the inputs reversed so lets just do that
int[] GetCompliment(int[] a, int[] b) { return GetDifference(b, a); }

// Get an array of all elements in a that are not in b
int[] GetDifference(int[] a, int[] b) 
{
    // Create the buffer array at the worst-case length which is the length
    // of a (where none of the elements in a are in b)
    int[] c = new int[a.Length];

    // Track how many elements we are actually ending up with
    int length = 0;

    // Loop through every element in a
    foreach (var ax in a)
    {
        bool found = false;
        // Loop through every element in b to see if it exists in a
        foreach (var bx in b)
        {
            if (ax == bx)
            {
                // If the element was found in b, there's no reason to keep looping
                found = true;
                break;
            }
        }

        // Only save the element if it was not found in b
        if (!found)
        {
            c[length] = ax;
            length++;
        }
    }

    // Create the result array using the length of actual elements found
    int[] result = new int[length];

    // Copy the relevant slice of the buffer array into the result array
    Array.Copy(c, result, length);

    // Return the result array
    return result;
}

Usage:

int[] a = { 1, 2, 3, 4 };
int[] b = { 3, 4, 5, 6, 7, 8 };
int[] c = GetDifference(a, b);
        
foreach(var cx in c)
{
    Console.Write(cx + ", ");   
}
        
Console.WriteLine();
int[] d = GetCompliment(a, b);
        
foreach(var dx in d)
{
    Console.Write(dx + ", ");   
}

// Output:
// 1, 2, 
// 5, 6, 7, 8

DotNetFiddle