2

I have a pair of values int x and int y and would like to see if this pair of values appear in an 2D array of pairs of values.

Typically, what I have now is:

if ((x == 5 && y == 2) || (x == 6 && y == 1) || ETC)
    return true;

Since there are quite a few possibilities that need to return true, I figured it would be easier to create an array with those pairs of values and see if x and y appear together as a pair in that array:

int[,] arrayOfPairs = new int[,]
    {
        {5, 2},
        {6, 1},
    };

I know in C++ we can use std::find to do that but don't know if it is possible in C#.

Thanks for your help!

4 Answers 4

3

Try using an array of Tuple<int, int>... For example:

Tuple<int, int>[] pairs = new Tuple<int, int>[]
{
    Tuple.Create(5, 2),
    Tuple.Create(6, 1),
};

Then you can determine if an element exists like so:

if (Array.IndexOf(pairs, Tuple.Create(3, 4)) != -1)
{
    // element exists.
}

There are slicker ways to do this w/ LINQ as well:

if (pairs.Any(x => x == Tuple.Create(3, 4)))
{
    // element exists
}

Per @Martheen's suggestion, here is how to implement using a HashSet.

HashSet<Tuple<int, int>> pairs = new HashSet<Tuple<int, int>>()
{
    Tuple.Create(5, 2),
    Tuple.Create(6, 1),
};

Which can be use as follows:

if (pairs.Contains(Tuple.Create(3, 4)))
{
    // element exists
}

Since you are using Unity, you could substitute a Tuple for a Vector2. Then my first method will work.

Also, if you want to get the speed benefits of using a HashSet but don't have access to that collection, then you could use a regular old Hashtable.

// initialize pairs
Hashtable pairs = new Hashtable().
pairs.Add(new Vector2(5F, 2F), true);
pairs.Add(new Vector2(6F, 1F), true);

// check for existence
if (pairs.ContainsKey(new Vector2(3F, 4F))
{
    // element exists
}
Sign up to request clarification or add additional context in comments.

3 Comments

Since Tuple also implement the Equals and GetHashCode, it can be faster to use HashSet instead of regular Array, since .Contains is O(1) instead of O(n). This assume large enough n and frequent comparison to bother.
Thanks so much! The problem is I'm using this on Unity 3D which is stuck at .NET 2.0 which does not support Tuples. Any way I can do this without having to use Tuples?
@Cyril_n - answer has been updated to use Unity data structures
3

Note that int[,] arrayOfPairs is a multi-dimensional array. It is not an array of pairs, and it’s not even an array of arrays. When accessing items, you will need two indices, which will basically confuse the relationship those two numbers have as part of their pair.

Instead, you should use an actual array of arrays: int[][]. That way, e.g. the first element of that array will be an array of members of the pair. Of course, this structure will not enforce any dimensions, so you cannot actually be sure that an element of that array is a 2-element array.

int[][] arrayOfPairs = new int[][]
{
    new int[] { 5, 2 },
    new int[] { 6, 1 },
};

A better solution is to use something that will actually enforce that there is a complete pair, i.e. exactly 2 elements. You can use the Tuple type for this, or even come up with your own type for this purpose. The Tuple type already comes with a good equality comparer, so you can use it well for your purpose. You can even put them in a set for quick membership tests:

var pairs = new HashSet<Tuple<int, int>>()
{
    Tuple.Create(5, 2),
    Tuple.Create(6, 1)
};

Console.WriteLine(pairs.Contains(Tuple.Create(5, 3))); // false
Console.WriteLine(pairs.Contains(Tuple.Create(5, 2))); // true

One final note: Your original condition does not really make much sense:

if ((x == 5 && y == 2) && (x == 6 && y == 1) && ETC)

It’s impossible for x, y to be 5, 2 and 6, 1 at the same time, so that condition would be always false.


If you have to use .NET 2.0 which does not have tuples, you can simply create your own type for this purpose:

public struct Pair
{
    public int X { get; set; }
    public int Y { get; set; }

    public Pair(int x, int y)
    {
        X = x;
        Y = y;
    }

    public override bool Equals(object other)
    {
        var otherPair = other as Pair?;
        return otherPair != null && otherPair.Value.X == X && otherPair.Value.Y == Y;
    }

    public override int GetHashCode()
    {
        return (17 + X.GetHashCode()) * 23 + Y.GetHashCode();
    }
}

And then your example would look like this:

var pairs = new HashSet<Pair>()
{
    new Pair(5, 2),
    new Pair(6, 1)
};

Console.WriteLine(pairs.Contains(new Pair(5, 3))); // false
Console.WriteLine(pairs.Contains(new Pair(5, 2))); // true

If you want to keep it as an array of arrays, you can also write your own Enumerable.Contains method (LINQ came with .NET 3.5):

public bool Contains(int[][] array, int[] item)
{
    foreach (int[] elem in array)
    {
        if (elem.Length != 2)
            throw new ArgumentException("Array element length should be exactly 2", "array");

        if (elem[0] == item[0] && elem[1] == item[1])
            return true;
    }

    return false;
}

Used like this:

Console.WriteLine(Contains(arrayOfPairs, new int[] { 5, 2 })); // true
Console.WriteLine(Contains(arrayOfPairs, new int[] { 5, 1 })); // false

3 Comments

Thanks, the first solution seems perfect since I cannot use Tuple with Unity3D. I'm however wondering how to test that my coordinate appear in that array of arrays.
@Cyril_n Added an example using a custom type. If you do a lot membership tests, you should do that instead of using an array of arrays, since that’s a lot more efficient then.
Thanks a million for your help!
0

Try doing it using Objects .

class pair
{
     int x;
     int y;
}

Store all of your pair objects in List. And when you are comparing against any value . Just iterate over the List of objects and see if any object has the same x and y coordinate.

Perhaps you may have to overload Equals() and GetHashCode() both if you are equating objects.

Comments

-2

Some people think LINQ query syntax is easiest to read:

    static void Main(string[] args)
    {
        int[][] arrayOfPairs = new int[][]
            {
                new int[] { 5, 2 },
                new int[] { 6, 1 },
            };

        System.Console.WriteLine(IsMatch(1, 3, arrayOfPairs));
        System.Console.WriteLine(IsMatch(5, 2, arrayOfPairs));
        System.Console.ReadKey();
    }

    static bool IsMatch(int x, int y, int[][] pairs)
    {
        var results = 
            from pair in pairs
            where pair[0] == x && pair[1] == y
            select pair;

        return results.Any();
    }

Outputs: False True

3 Comments

This method will always iterate the entire collection, which can be a performance issue.
I agree, and we should always consider performance. However, the question is not asking for the fastest way. Sometimes more readable code is better than the most optimized solution.
The fastest C# solution is likely the one using the HashSet. theburningmonk.com/2011/03/hashset-vs-list-vs-dictionary

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.