Is there is a way to sort 2D array based on one field ?
Mine is an array Card(suit, rank). I want to sort it based on rank.

Recommended Answers

All 9 Replies

Sure is, just add the interface IComparable to your Card class, then use the build in Array.Sort.

public int CompareTo(object obj)
{
  if (obj is Card)
  {
   return this.Rank_p.CompareTo((obj as Card).Rank_p);
  }
}

I created this Compareto class but I see a red line saying not all code returns a value. How do i get it to correct return type?

Memorath, how would you do that what you said? Would like to see that too.

Change the first line of your class to read

public Card : IComparable<Card> {

Then you need to define the compare function. We use the IComparble<> interface so we don't have to do casting and other stuff we don't want to do. This also means we can only compare Card with Card (which is what you want to do 99.9% of the time anyway).

Now, I don't know what type Rank is, but let us assume that it is some primitive type, like Int32:

public int CompareTo(Card other) {
    return this.rank.CompareTo(other.rank);
}

Now, if we wanted to take suit into consideration (as now it doesn't care, so they will be in some random suit order)

public int CompareTo(Card other) {
    int result = this.rank.CompareTo(other.rank);
    if (result == 0) {
        result = this.suit.CompareTo(other.suit);
    }

    return result;
}

Now, we don't have to add the IComparable interface if we don't want to, as you can pass a Comparer<T> to Array.Sort and it will use that to compare the objects. You'd do it this way if you wanted to be able to sort something in different ways. Taking your Card class as an example, we might want to sort on Suit then Rank, or Rank then Suit. But that's a different post, ask if you want to see it done that way, also.

I've never found an elegant way to do that:

using System;
using System.Linq;

namespace DW_418578_CS_CON
{
   class Program
          private static int[][] SortByColumn(int intColumn, int[,] arr_int)
   {
          private static int[][] SortByColumn(int intColumn, int[,] arr_int)
      {
         int intHeight = arr_int.GetUpperBound(0) + 1;
         int intWidth = arr_int.GetUpperBound(1) + 1;

         return
         (
            from i in Enumerable.Range(0, intHeight)
            let lst_intEachRow = arr_int.OfType<int>().ToList().GetRange(i * intWidth, intWidth)
            orderby lst_intEachRow[intColumn]
            select lst_intEachRow.ToArray()
         ).ToArray();
      }

      private static void DisplayArray(int[][] arr_int)
      {
         int intHeight = arr_int.GetUpperBound(0) + 1;

         for (int i = 0; i < intHeight; i++)
         {
            Console.WriteLine("{0}-{1}", arr_int[i][0], arr_int[i][1]);
         }
      }

      private static void DisplayArray(int[,] arr_int)
      {
         int intHeight = arr_int.GetUpperBound(0) + 1;

         for (int i = 0; i < intHeight; i++)
         {
            Console.WriteLine("{0}-{1}", arr_int[i,0], arr_int[i,1]);
         }
      }

      static void Main(string[] args)
      {
         int[,] arr_int = new int[,] { { 1, 1 }, { 156, 2 }, { 3, 4 }, { 15, 2 } };
         Console.WriteLine("--- before ---");
         DisplayArray(arr_int);

         int[][] arr_int_sorted = SortByColumn(0, arr_int);
         Console.WriteLine("--- after1 ---");
         DisplayArray(arr_int_sorted);

         arr_int_sorted = SortByColumn(1, arr_int);
         Console.WriteLine("--- after2 ---");
         DisplayArray(arr_int_sorted);
      }
   }
}

This looks pretty neat doesn`t it :)

MEMORATH: is this what you were talking about?

Yes, Mitja, that's the IComparable interface. In my example, though, I used IComparable<T> as it does some stuff for you that you'd have to handle with just using IComparable

Arrays aren't very suited for C#, in a language like C++ this problem would be much simpler since you can treat a multidimensional array like a flat array. Linq doesn't play nicely with arrays, and neither do many .net objects.

In C# you need to convert it, which is a bit ugly. Here's a working example of what I think you are trying to do in C#:

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;

namespace ConsoleApplication4
{
    class Program
    {
        static void Main(string[] args)
        {
            Random ran = new Random();
            int iWidth = ran.Next(1, 8);
            int iHeight = ran.Next(1, 8);
            card[,] cards = new card[iWidth, iHeight];
            for (int i = 0; i < iWidth; i++)
                for (int ii = 0; ii < iHeight; ii++)
                    cards[i, ii] = new card { rank = ran.Next(1, 14), suit = ran.Next(1, 5) };

            Console.WriteLine("Unsorted:");
            for (int i = 0; i < iWidth; i++)
            {
                Console.Write(Environment.NewLine);
                for (int ii = 0; ii < iHeight; ii++)
                    Console.Write(string.Format("({0},{1}) ", cards[i, ii].rank, cards[i, ii].suit));
            }

            sortbyrank(ref cards);

            Console.WriteLine(Environment.NewLine + Environment.NewLine + "Sorted:");
            for (int i = 0; i < iWidth; i++)
            {
                Console.Write(Environment.NewLine);
                for (int ii = 0; ii < iHeight; ii++)
                    Console.Write(string.Format("({0},{1}) ", cards[i, ii].rank, cards[i, ii].suit));
            }
            Console.ReadKey();
        }

        struct card
        {
            public int rank;
            public int suit;
        }
        static void sortbyrank(ref card[,] toSort)
        {
            int iWidth = toSort.GetUpperBound(0) + 1;
            int iHeight = toSort.GetUpperBound(1) + 1;
            //create a 1d array to flatten the 2d one into
            card[] flattened = new card[iWidth * iHeight];
            for (int i = 0; i < iWidth; i++)
                for (int ii = 0; ii < iHeight; ii++)
                    flattened[(i * iHeight) + ii] = toSort[i, ii];
            //order by rank
            flattened = flattened.OrderBy(x => x.rank).ToArray();
            //unflatten the sorted array into the argument reference
            for (int i = 0; i < flattened.Length; i++)
               // toSort[i / iWidth,i % iWidth] 
                toSort[i / iHeight, i % iHeight] = flattened[i];
        }
    }

Hmm...apperantly code tags have changed. There no syntax highlighting and I can't edit my post :S

commented: Your post looks fine to me. +13
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.