Reputation: 1488
Consider I have objects Foo and Bar; and 3 tuples named A, B and C.
A = (Foo, Bar)
B = (Bar, Foo)
C = (Foo, Bar)
I want to know if their elements are the same, not taking order of elements into account. So my desired results are;
A.HasSameElementsWith(B) -> True
A.HasSameElementsWith(C) -> True
B.HasSameElementsWith(C) -> True
I know I can run a nested loop to compare them for each of their elements. Something along the lines of:
foreach (itemA in A)
{
bool flag = false;
foreach (itemB in B)
{
if(itemA == itemB)
{
flag = true;
break;
}
}
if (!flag) return false;
}
return true;
But this seems inefficient. Is there a more convinient way to do this?
Note:
I'm using generics, so Foo
and Bar
can be of any type. But they will be the same type with each other. (i.e. The type of Foo
will be the same with the type of Bar
)
Upvotes: 3
Views: 2056
Reputation: 244757
If you have two 2-tuples, then there are only two options for them to be equal according to your rules and you can write that as an almost one-liner method:
public static bool HasSameElementsWith<T>(this (T, T) tuple1, (T, T) tuple2) =>
(Equals(tuple1.Item1, tuple2.Item1) && Equals(tuple1.Item2, tuple2.Item2)) ||
(Equals(tuple1.Item1, tuple2.Item2) && Equals(tuple1.Item2, tuple2.Item1));
If you can have more than two items per tuple, then I would start to consider them to be a collection and the question then becomes if two collections have the same items. And to do that, you can count up each item in the first collection in a Dictionary<T, int>
, and then count down the items from the second collection. If both collections contain the same items, all counts should be zero at the end. (If you're sure items in each collection are unique, you could use HashSet<T>
instead.) In code:
public static bool HasSameElementsWith<T>(
this IEnumerable<T> collection1, IEnumerable<T> collection2)
{
var counts = new Dictionary<T, int>();
foreach (var item in collection1)
{
counts.TryGetValue(item, out int count);
count++;
counts[item] = count;
}
foreach (var item in collection2)
{
counts.TryGetValue(item, out int count);
if (count == 0)
return false;
count--;
counts[item] = count;
}
return counts.Values.All(c => c == 0);
}
Now you can implement the tuple version of HasSameElementsWith
on top of the collection version:
public static bool HasSameElementsWith<T>(this (T, T) tuple1, (T, T) tuple2) =>
HasSameElementsWith(tuple1.ToArray(), tuple2.ToArray());
public static T[] ToArray<T>(this (T, T) tuple) => new[] { tuple.Item1, tuple.Item2 };
Upvotes: 4
Reputation: 37337
I will exapnd @doctorlove comment a little. He mentioned sorting. Once you have sorted it, you can compare them element by element. Pseudo code:
public bool Compare(A, B){
return (A[1] == B[1] & A[2] == B[2]);
}
Upvotes: 0