views:

1252

answers:

11

hi ,

i am trying to tally two arrays like myArray{a,b,c} and urArray{a,b,c,c}

i wanted to check if both the elements have same elements ,for example in above condition the second array that is 'urArray' has an extra 'c' .

and the code should be able to equate two sets of array if they have the same elements or not and the order of the elements doesn't matter just that both array should have same elements i.e if one has two 'c' the other should also have two 'c' otherwise the condition is false

so what i did was:

char[] myArray = new char[] {'a','b','c','c'};
char[] urArray = new char[] { 'a', 'b', 'c' ,'a'};
List<char> tmp2 = new List<char>(urArray);

 for (int i = 0; i < myArray.Length; ++i)
            {
                for (int j = 0; j < urArray.Length; ++j)
                {
                    if (myArray[i] == urArray[j])
                    {

                        System.Console.WriteLine(urArray[j] + "--> " + "urArray"+"  myArray"+"--> "+myArray[i]);
                        tmp2.Remove(urArray[j]);

                        urArray = tmp2.ToArray();

                    }
                    else if (myArray[i] != urArray[j])
                    {
                        System.Console.WriteLine(myArray[i] + "--> " + "myArray" + "  urArray" + "--> " + urArray[j]);
                    }
                }

            }

but have no idea how to show that if the array have same elements or not ...

how can i accomplish this?

+3  A: 

This seems like the same issue I had: Comparing Two Collections for Equality

GoodEnough
Why do you perform this complex key look-up in your solution? Why not just ContainsKey()? You have comments in your code saying that the dictionary uses reference equality, but that is not true. If TKey is a value type, there is no reference equality at all. Could you elaborate on this? Maybe I am missing an important point.
Daniel Brückner
If a collection contains two of the same, but the other collection contains only once, if I don't do key look-ups with counters, I won't know that the collections are different. I also mention that the code as it is compares for equality. If the objects are reference-type (objects), then their reference will be compared. So if I have two instances of the same object, they won't be equal.
GoodEnough
+4  A: 

You could sort the two arrays and then sequentially compare elements. If at any time the two elements being compared are different the arrays contain different elements.

David Johnstone
A: 

I think what you are meaning is you want to basically check if both arrays have the same elements in them.

firstly, small improvement, you can initalize a List object via the contructor rather than creating separate arrays e.g.

List<string> list = new List<string>() {"A", "B", "C"}

To resolve the above issue I would just create a method that takes in 2 lists and returns a boolean something like:

public Boolean IsEqual(List<char> list1, List<char> list2, List<char> duplicates)
{
      var matched = new List<char>();
      foreach (var c in list2)
      {
           if (matched.Contains(c))
           {
                duplicates.Add(c);
           }
           else
           {
                if (list1.Contains(c))
                {
                    matched.Add(c);
                }
                else
                {
                     return false;
                }    
           }
      }

      return true;
}

Then you can handle the situation accordingly e.g.

if (isEqual(myList, urList, duplicates))
{
      Console.WriteLine("Lists are equal!");
      // loop through duplicates
}
else
{
      Console.WriteLine("Lists are not equal!");
}

Hope that helps.

UPDATED:

I have updated this solution to support capturing the duplicates and still comparing the lists for equality.

James
i need to have same elements like if there are two 'c' in one array and one 'c' in another then will this solution work?
jarus
i need to check number of elements plus the exact elements in both the arrays , i think the above solution only checks if the elements are there ,i.e if there is one 'c' in one array and two 'c' in another then also the above would give lists are equal , but i don't want that ..., so how can i achieve that ?
jarus
It will not work in the general case - for example if one list has a duplicate it will work, because the lengths will differ, but it will not work if one list has two A's and one list two B's.
Daniel Brückner
I don't quite understand what it is your trying to achieve. This solution will return and tell you if the lists are equal is that not what you asked?
James
So you want the solution not to take into account duplicates?
James
what if like for example one array has {p,o,l,l} and the another array has {p,o,o,l} ,will the above solution give they are equal or they are not equal ?in this condition i want to return "the array are not equal"
jarus
yeah ,i want to equate the duplicates also...
jarus
So you want to compare 2 lists, and output what values where duplicated and how many times it was duplicated? You only want to say the lists are not equal when a value is not found in the opposing list?
James
+2  A: 

I suggest to calculate the difference between the histograms of both sequences. This will even work if the sequence cannot be sorted or there is no efficient way to determine the length of a sequence.

public static Boolean CompareCollections<T>(IEnumerable<T> a, IEnumerable<T> b)
{
    Dictionary<T, Int32> histogram = new Dictionary<T, Int32>();

    foreach (T item in a)
    {
        Int32 count;
        if (histogram.TryGetValue(item, out count))
        {
            histogram[item]++;
        }
        else
        {
            histogram[item] = 1;
        }
    }

    foreach (T item in b)
    {
        Int32 count;
        if (histogram.TryGetValue(item, out count))
        {
            if (count <= 0)
            {
                return false;
            }

            histogram[item]--;
        }
        else
        {
            return false;
        }
    }

    foreach (Int32 value in histogram.Values)
    {
        if (value != 0)
        {
            return false;
        }
    }

    return true;
}

If the length of the sequence can be obtained, checking all values in the dictionary to be zero can be replaced by an check for equal sequence lengths.

public static Boolean CompareCollections<T>(ICollection<T> a, ICollection<T> b)
{
    if (a.Count != b.Count)
    {
        return false;
    }

    Dictionary<T, Int32> histogram = new Dictionary<T, Int32>();

    foreach (T item in a)
    {
        Int32 count;
        if (histogram.TryGetValue(item, out count))
        {
            histogram[item]++;
        }
        else
        {
            histogram[item] = 1;
        }
    }

    foreach (T item in b)
    {
        Int32 count;
        if (histogram.TryGetValue(item, out count))
        {
            if (count <= 0)
            {
                return false;
            }

            histogram[item]--;
        }
        else
        {
            return false;
        }
    }

    return true;
}

This solution is O(n) if the costs of building the dictionary are negligible while sorting requires O(n*log(n)) time.

Daniel Brückner
A: 

If your arrays only contain unique elements, I would create two HashSets from them and then subtract one from the other to see if the result is the empty set.

zvolkov
The question is tagged as "visualstudio2005". If that's the case then HashSet wouldn't be available.
LukeH
@Luke hmm... I didn't notice you might be right.
zvolkov
+1  A: 

This is a one-liner with LINQ:

bool same = !array1.Except (array2).Any() && !array2.Except (array1).Any();

Alternatively, you could call OrderBy on each sequence to sort them in the same order and then use Enumerable.SequenceEqual to compare them:

bool same = Enumerable.SequenceEqual (array1.OrderBy (n => n), array2.OrderBy (n => n));
Joe Albahari
The first version is incorrect as it will incorrectly report arrays of different sizes as being equivalent, as well as not correctly dealing with duplicates.The second version will be correct. Sort then compare sequences.
LBushkin
Yes - you're quite correct. Given the question, Except() won't do the job.
Joe Albahari
The question is tagged as "visualstudio2005" which suggests that a non-LINQ solution is required.
LukeH
+5  A: 

Here's some C# code using linq that should do the job, it's basically an implementation of the sort/compare sequence form - which is the most reliable. This code will sort both sequences and compare the for equivalence. You could optimize it slightly, by first checking that myArray and urArray are of the same length, to avoid unnecessary sorting.

char[] myArray = new char[] {'a','b','c','c'};
char[] urArray = new char[] { 'a', 'b', 'c' ,'a'};

var areEqual = myArray.OrderBy( x => x )
                      .SequenceEqual( urArray.OrderBy( x => x ) );

If you can't (or don't want to) use linq for some reason, here is an equivalent version using .NET 2.0 code:

public static bool AreEquivalentArray( char[] a, char[] b )
        {
            if (a.Length != b.Length)
                return false;

            Array.Sort(a);
            Array.Sort(b);
            for (int i = 0; i < a.Length; i++)
            {
                if( !a[i].Equals( b[i] ) )
                    return false;
            }
            return true;
        }
LBushkin
The question is tagged as "visualstudio2005" which suggests that a non-LINQ solution is required.
LukeH
The solution must be able to handle the arrays being of different lengths as there could be duplicates
James
This is not how I understood it, the original question states:"equate two sets of array if they have the same elements or not and the order of the elements doesn't matter just that both array should have same elements i.e if one has two 'c' the other should also have two 'c' otherwise the condition is false"
LBushkin
My original solution did just that and I was told it was wrong so I assumed jarus wanted some form of handling to deal with duplicates....I may be wrong lol
James
A: 

If you're unable to use LINQ then this should do the trick:

char[] myArray = new char[] { 'a', 'b', 'c', 'c' };
char[] urArray = new char[] { 'a', 'b', 'c' ,'a' };

Console.WriteLine(AreEqual(myArray, urArray));    // False

// ...

public bool AreEqual<T>(IEnumerable<T> first, IEnumerable<T> second)
{
    Dictionary<T, int> map = new Dictionary<T, int>();

    foreach (T item in first)
    {
        if (map.ContainsKey(item))
            map[item]++;
        else
            map[item] = 1;
    }

    foreach (T item in second)
    {
        if (map.ContainsKey(item))
            map[item]--;
        else
            return false;
    }

    foreach (int i in map.Values)
    {
        if (i != 0)
            return false;
    }
    return true;
}
LukeH
A: 
James
A: 

First you one should check if the arrays are the same length.

If they are then we need to sort the arrays.

Then loop through both arrays and compare each element.

    char[] myArray = new char[] { 'a', 'b', 'c', 'c' };
    char[] urArray = new char[] { 'a', 'b', 'c', 'a' };


    if (myArray.Length.Equals(urArray.Length))
    {
        ///
        /// sort arrays
        ///

        System.Array.Sort(myArray);
        System.Array.Sort(urArray);

        for (int i = 0; i < myArray.Length; i++)
        {
            if (myArray[i] != urArray[i])
            {
                ///
                /// Arrays do not have same elements.
                ///
                break;

            }

        }
        ///
        /// if reach this code path the two arrays are equal.
        ///


    } else
    {
        ///
        /// Arrays not equal lenght
        ///

    }
TonyAbell
+1  A: 
return myArray.OrderBy(c => c).SequenceEqual(urArray.OrderBy(c => c));
m1k4