Как отсортировать двумерный (прямоугольный) массив в C #? - PullRequest
33 голосов
/ 24 октября 2008

У меня есть двумерный массив (из строк), который составляет мою таблицу данных (из строк и столбцов). Я хочу отсортировать этот массив по любому столбцу. Я пытался найти алгоритм для этого в C #, но безуспешно.

Любая помощь приветствуется.

Ответы [ 12 ]

40 голосов
/ 24 октября 2008

Могу я проверить - вы имеете в виду прямоугольный массив ([,]) или зубчатый массив ([][])?

Довольно просто отсортировать зубчатый массив; У меня есть обсуждение этого здесь . Очевидно, что в этом случае Comparison<T> будет включать в себя столбец вместо сортировки по порядковому номеру - но очень похоже.

Сортировка прямоугольного массива сложнее ... Возможно, у меня возникнет соблазн скопировать данные либо в прямоугольный массив, либо в List<T[]>, и отсортировать там , а затем скопировать обратно.

Вот пример использования зубчатого массива:

static void Main()
{  // could just as easily be string...
    int[][] data = new int[][] { 
        new int[] {1,2,3}, 
        new int[] {2,3,4}, 
        new int[] {2,4,1} 
    }; 
    Sort<int>(data, 2); 
} 
private static void Sort<T>(T[][] data, int col) 
{ 
    Comparer<T> comparer = Comparer<T>.Default;
    Array.Sort<T[]>(data, (x,y) => comparer.Compare(x[col],y[col])); 
} 

Для работы с прямоугольным массивом ... ну, вот код, который можно поменять местами на лету ...

static T[][] ToJagged<T>(this T[,] array) {
    int height = array.GetLength(0), width = array.GetLength(1);
    T[][] jagged = new T[height][];

    for (int i = 0; i < height; i++)
    {
        T[] row = new T[width];
        for (int j = 0; j < width; j++)
        {
            row[j] = array[i, j];
        }
        jagged[i] = row;
    }
    return jagged;
}
static T[,] ToRectangular<T>(this T[][] array)
{
    int height = array.Length, width = array[0].Length;
    T[,] rect = new T[height, width];
    for (int i = 0; i < height; i++)
    {
        T[] row = array[i];
        for (int j = 0; j < width; j++)
        {
            rect[i, j] = row[j];
        }
    }
    return rect;
}
// fill an existing rectangular array from a jagged array
static void WriteRows<T>(this T[,] array, params T[][] rows)
{
    for (int i = 0; i < rows.Length; i++)
    {
        T[] row = rows[i];
        for (int j = 0; j < row.Length; j++)
        {
            array[i, j] = row[j];
        }
    }
}
26 голосов
/ 24 октября 2008

Загрузите массив двумерных строк в фактическую таблицу данных (System.Data.DataTable), а затем используйте метод Select () объекта DataTable, чтобы создать отсортированный массив объектов DataRow (или использовать DataView для аналогичного эффекта). .

// assumes stringdata[row, col] is your 2D string array
DataTable dt = new DataTable();
// assumes first row contains column names:
for (int col = 0; col < stringdata.GetLength(1); col++)
{
    dt.Columns.Add(stringdata[0, col]);
}
// load data from string array to data table:
for (rowindex = 1; rowindex < stringdata.GetLength(0); rowindex++)
{
    DataRow row = dt.NewRow();
    for (int col = 0; col < stringdata.GetLength(1); col++)
    {
        row[col] = stringdata[rowindex, col];
    }
    dt.Rows.Add(row);
}
// sort by third column:
DataRow[] sortedrows = dt.Select("", "3");
// sort by column name, descending:
sortedrows = dt.Select("", "COLUMN3 DESC");

Вы также можете написать свой собственный метод для сортировки двумерного массива. Оба подхода были бы полезны для обучения, но подход DataTable поможет вам освоить лучший способ обработки таблиц данных в приложении C #.

6 голосов
/ 24 октября 2008

Здесь - это архивированная статья Джима Мишеля из InformIt, которая занимается сортировкой как прямоугольных, так и зубчатых многомерных массивов.

1 голос
/ 21 января 2013

Можно также посмотреть на Array.Sort Method http://msdn.microsoft.com/en-us/library/aa311213(v=vs.71).aspx

например. Array.Sort (массив, делегат (объект [] x, объект [] y) {return (x [i] как IComparable) .CompareTo (y [i]);});

из http://channel9.msdn.com/forums/Coffeehouse/189171-Sorting-Two-Dimensional-Arrays-in-C/

1 голос
/ 26 июня 2011
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int[,] arr = { { 20, 9, 11 }, { 30, 5, 6 } };
            Console.WriteLine("before");
            for (int i = 0; i < arr.GetLength(0); i++)
            {
                for (int j = 0; j < arr.GetLength(1); j++)
                {
                    Console.Write("{0,3}", arr[i, j]);
                }
                Console.WriteLine();
            }
            Console.WriteLine("After");

            for (int i = 0; i < arr.GetLength(0); i++) // Array Sorting
            {
                for (int j = arr.GetLength(1) - 1; j > 0; j--)
                {

                    for (int k = 0; k < j; k++)
                    {
                        if (arr[i, k] > arr[i, k + 1])
                        {
                            int temp = arr[i, k];
                            arr[i, k] = arr[i, k + 1];
                            arr[i, k + 1] = temp;
                        }
                    }
                }
                Console.WriteLine();
            }

            for (int i = 0; i < arr.GetLength(0); i++)
            {
                for (int j = 0; j < arr.GetLength(1); j++)
                {
                    Console.Write("{0,3}", arr[i, j]);
                }
                Console.WriteLine();
            }
        }
    }
}
1 голос
/ 24 октября 2008

Этот код должен делать то, что вам нужно, я не обобщил его на n, но это прямо. Тем не менее, я согласен с MusiGenesis, используя другой объект, который немного лучше подходит для этого (особенно, если вы собираетесь делать какие-либо виды связывания)

(я нашел код здесь )

string[][] array = new string[3][];

array[0] = new string[3] { "apple", "apple", "apple" };
array[1] = new string[3] { "banana", "banana", "dog" };
array[2] = new string[3] { "cat", "hippo", "cat" };         

for (int i = 0; i < 3; i++)
{
   Console.WriteLine(String.Format("{0} {1} {2}", array[i][0], array[i][1], array[i][2]));
}

int j = 2;

Array.Sort(array, delegate(object[] x, object[] y)
  {
    return (x[j] as IComparable).CompareTo(y[ j ]);
  }
);

for (int i = 0; i < 3; i++)
{
  Console.WriteLine(String.Format("{0} {1} {2}", array[i][0], array[i][1], array[i][2]));
}
0 голосов
/ 02 июля 2016

Я знаю, что уже поздно, но вот моя мысль, которую вы могли бы рассмотреть.

например, это массив

{
m,m,m
a,a,a
b,b,b
j,j,j
k,l,m
}

и вы хотите преобразовать его в столбец номер 2, затем

string[] newArr = new string[arr.length]
for(int a=0;a<arr.length;a++)
newArr[a] = arr[a][1] + a;
// create new array that contains index number at the end and also the coloumn values
Array.Sort(newArr);
for(int a=0;a<newArr.length;a++)
{
int index = Convert.ToInt32(newArr[a][newArr[a].Length -1]);
//swap whole row with tow at current index
if(index != a)
{
string[] arr2 = arr[a];
arr[a] = arr[index];
arr[index] = arr2;
}
}

Поздравляем, вы отсортировали массив по желаемому столбцу. Вы можете отредактировать это, чтобы оно работало с другими типами данных

0 голосов
/ 15 августа 2013

Это старый вопрос, но вот класс, который я только что построил на основе статьи Джима Мишеля из InformIt , связанной с Дугом Л.

class Array2DSort : IComparer<int>
{
    // maintain a reference to the 2-dimensional array being sorted
    string[,] _sortArray;
    int[] _tagArray;
    int _sortIndex;

    protected string[,] SortArray { get { return _sortArray; } }

    // constructor initializes the sortArray reference
    public Array2DSort(string[,] theArray, int sortIndex)
    {
        _sortArray = theArray;
        _tagArray = new int[_sortArray.GetLength(0)];
        for (int i = 0; i < _sortArray.GetLength(0); ++i) _tagArray[i] = i;
        _sortIndex = sortIndex;
    }

    public string[,] ToSortedArray()
    {
        Array.Sort(_tagArray, this);
        string[,] result = new string[
            _sortArray.GetLength(0), _sortArray.GetLength(1)];
        for (int i = 0; i < _sortArray.GetLength(0); i++)
        {
            for (int j = 0; j < _sortArray.GetLength(1); j++)
            {
                result[i, j] = _sortArray[_tagArray[i], j];
            }
        }
        return result;
    }

    // x and y are integer row numbers into the sortArray
    public virtual int Compare(int x, int y)
    {
        if (_sortIndex < 0) return 0;
        return CompareStrings(x, y, _sortIndex);
    }

    protected int CompareStrings(int x, int y, int col)
    {
        return _sortArray[x, col].CompareTo(_sortArray[y, col]);
    }
}

Учитывая несортированный двумерный массив data произвольного размера, который вы хотите отсортировать в столбце 5, вы просто делаете это:

        Array2DSort comparer = new Array2DSort(data, 5);
        string[,] sortedData = comparer.ToSortedArray();

Обратите внимание на виртуальный метод Compare и защищенный SortArray, так что вы можете создавать специализированные подклассы, которые всегда сортируют по определенному столбцу или выполняют специализированную сортировку по нескольким столбцам или тому, что вы хотите сделать. Именно поэтому CompareStrings взломан и защищен - любые подклассы могут использовать его для простых сравнений вместо ввода полного синтаксиса SortArray[x, col].CompareTo(SortArray[y, col]).

0 голосов
/ 01 июля 2010

Мне нравится подход DataTable, предложенный MusiGenesis выше. Приятно то, что вы можете сортировать по любой допустимой строке SQL 'order by', которая использует имена столбцов, например, «x, y desc, z» для «порядка по x, y desc, z». (FWIW, я не мог заставить его работать, используя порядковые номера столбцов, например, «3,2,1» для «порядка на 3,2,1»). Я использовал только целые числа, но ясно, что вы можете добавить данные смешанного типа в DataTable Сортировать это любым способом.

В приведенном ниже примере я сначала загрузил некоторые несортированные целочисленные данные в tblToBeSorted в песочнице (не показано). Поскольку таблица и ее данные уже существуют, я загружаю ее (не отсортированную) в двумерный целочисленный массив, затем в DataTable. Массив DataRows является отсортированной версией DataTable. Пример немного странный в том, что я загружаю свой массив из БД и мог бы отсортировать его тогда, но я просто хотел получить несортированный массив в C # для использования с объектом DataTable.

static void Main(string[] args)
{
    SqlConnection cnnX = new SqlConnection("Data Source=r90jroughgarden\\;Initial Catalog=Sandbox;Integrated Security=True");
    SqlCommand cmdX = new SqlCommand("select * from tblToBeSorted", cnnX);
    cmdX.CommandType = CommandType.Text;
    SqlDataReader rdrX = null;
    if (cnnX.State == ConnectionState.Closed) cnnX.Open();

    int[,] aintSortingArray = new int[100, 4];     //i, elementid, planid, timeid

    try
    {
        //Load unsorted table data from DB to array
        rdrX = cmdX.ExecuteReader();
        if (!rdrX.HasRows) return;

        int i = -1;
        while (rdrX.Read() && i < 100)
        {
            i++;
            aintSortingArray[i, 0] = rdrX.GetInt32(0);
            aintSortingArray[i, 1] = rdrX.GetInt32(1);
            aintSortingArray[i, 2] = rdrX.GetInt32(2);
            aintSortingArray[i, 3] = rdrX.GetInt32(3);
        }
        rdrX.Close();

        DataTable dtblX = new DataTable();
        dtblX.Columns.Add("ChangeID");
        dtblX.Columns.Add("ElementID");
        dtblX.Columns.Add("PlanID");
        dtblX.Columns.Add("TimeID");
        for (int j = 0; j < i; j++)
        {
            DataRow drowX = dtblX.NewRow();
            for (int k = 0; k < 4; k++)
            {
                drowX[k] = aintSortingArray[j, k];
            }
            dtblX.Rows.Add(drowX);
        }

        DataRow[] adrowX = dtblX.Select("", "ElementID, PlanID, TimeID");
        adrowX = dtblX.Select("", "ElementID desc, PlanID asc, TimeID desc");

    }
    catch (Exception ex)
    {
        string strErrMsg = ex.Message;
    }
    finally
    {
        if (cnnX.State == ConnectionState.Open) cnnX.Close();
    }
}
0 голосов
/ 26 октября 2008

Если бы вы могли получить данные в виде универсального кортежа, когда читали или извлекали их, это было бы намного проще; тогда вам просто нужно написать функцию Sort, которая сравнивает желаемый столбец кортежа, и у вас есть массив измерений с одним измерением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...