Home > Back-end >  Compare two multidimensional arrays in C#
Compare two multidimensional arrays in C#

Time:01-06

I want to write some logic in c# for two multidimensional arrays. I know that I can use SequenceEqual to verify and return true if they are in the same order How would I still return true, if the arrays inside the multidimensional array had elements in different locations?

using System;
using System.Collections;
using System.Linq;

class Program {
  public static void Main (string[] args) {
    string[,] actual = new string[,]
    {
      {"fruitname", "fruitcolor", "fruitshape"},
      {"banana", "yellow", "rectangle"},
      {"apple", "red", "round"}
    };

    string[,] user1 = new string[,]
    {
      {"fruitname", "fruitcolor", "fruitshape"},
      {"banana", "yellow", "rectangle"},
      {"apple", "red", "round"}
    };
    
    string[,] user2 = new string[,]
    {
      {"fruitshape", "fruitname", "fruitcolor"},
      {"rectangle", "banana", "yellow"},
      {"round", "apple", "red"}
    };
    
    Console.WriteLine(VerifyQueries(actual, user2));
  }

  public static bool VerifyQueries(string[,] storedQuery, string[,] userQuery) {
    // Check length & number of elements in the array
    if(storedQuery.Rank == userQuery.Rank &&
        Enumerable.Range(0,storedQuery.Rank)
        .All(dimension => storedQuery.GetLength(dimension) ==                                   userQuery.GetLength(dimension))
      )
    { 
      // Check if they are exactly the same, return true
      if(storedQuery.Cast<string>().SequenceEqual(userQuery.Cast<string>())) {
        return true;
      }

      //Check if they have matching elements in different index
      for(int i = 0; i < storedQuery.GetLength(0); i  ) {
        for(int j = 0; j < storedQuery.GetLength(1); j  ) {
          
        }
      }

    }
    return false;
  }
}

currently, I am returning true for actual and user1 arrays. I want to return true also for actual and user2.

CodePudding user response:

I think you could flatten the arrays to 1D array then sort them and compare as you are doing in your code.

var storedFlat = storedQuery.Cast<string>().OrderBy(x => x).ToArray();
var userFlat = userQuery.Cast<string>().OrderBy(x => x).ToArray();

return storedFlat.SequenceEqual(userFlat);

CodePudding user response:

Something like this should work:

public static bool VerifyQueries(string[,] storedQuery, string[,] userQuery)
{
    // Check length & number of elements in the array
    if (storedQuery.Rank != userQuery.Rank ||
        Enumerable.Range(0, storedQuery.Rank).Any(dimension => storedQuery.GetLength(dimension) != userQuery.GetLength(dimension)))
    {
        return false;
    }

    // Check if they are exactly the same, return true
    if (storedQuery.Cast<string>().SequenceEqual(userQuery.Cast<string>()))
    {
        return true;
    }

    static IEnumerable<string> row(string[,] array, int r) // Convenience method to return elements of one row.
    {
        for (int i = 0; i < array.GetLength(1);   i)
        {
            yield return array[r, i];
        }
    }

    //Check if they have matching elements in different index
    for (int i = 0; i < storedQuery.GetLength(0); i  )
    {
        if (row(storedQuery, i).Except(row(userQuery, i)).Any())
            return false;
    }

    return true;
}

Notes:

  1. I've changed the dimension check so that it returns false at the start of the method, to avoid unnecessary indentation.
  2. I've added a local method to enumerate the elements of one row - this simplifies the code somewhat.
  3. I'm checking if two rows differ by using .Except(). This will return an empty sequence if the two rows are identical ignoring order, or a non-empty sequence if the two rows contain different elements. Then I can use .Any() to determine if we need to return false (because a non-empty result means that the rows contain different elements).
  4. This uses .Except() rather than sorting, meaning it has O(N) complexity rather than O(N.Log(N))
  • Related