如何在 C# 中对二维(矩形)数组进行排序?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/232395/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:09:47  来源:igfitidea点击:

How do I sort a two-dimensional (rectangular) array in C#?

c#arrayssorting

提问by Hyman

I have a two-dimensional array (of Strings) which make up my data table (of rows and columns). I want to sort this array by any column. I tried to find an algorithm for doing this in C#, but have not been successful.

我有一个二维数组(字符串),它构成了我的数据表(行和列)。我想按任何列对这个数组进行排序。我试图在 C# 中找到一种算法,但没有成功。

Any help is appreciated.

任何帮助表示赞赏。

采纳答案by MusiGenesis

Load your two-dimensional string array into an actual DataTable (System.Data.DataTable), and then use the DataTable object's Select() method to generate a sorted array of DataRow objects (or use a DataView for a similar effect).

将您的二维字符串数组加载到实际的 DataTable (System.Data.DataTable) 中,然后使用 DataTable 对象的 Select() 方法生成一个已排序的 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");

You could also write your own method to sort a two-dimensional array. Both approaches would be useful learning experiences, but the DataTable approach would get you started on learning a better way of handling tables of data in a C# application.

您也可以编写自己的方法来对二维数组进行排序。这两种方法都是有用的学习经验,但 DataTable 方法会让您开始学习在 C# 应用程序中处理数据表的更好方法。

回答by Doug L.

Hereis an archived article from Jim Mischel at InformIt that handles sorting for both rectangular and jagged multi-dimensional arrays.

是 InformIt 的 Jim Mischel 的一篇存档文章,它处理矩形和锯齿状多维数组的排序。

回答by Moishe Lettvin

So your array is structured like this (I'm gonna talk in pseudocode because my C#-fu is weak, but I hope you get the gist of what I'm saying)

所以你的数组结构是这样的(我会用伪代码说话,因为我的 C#-fu 很弱,但我希望你明白我说的要点)

string values[rows][columns]

So value[1][3]is the value at row 1, column 3.

value[1][3]第 1 行第 3 列的值也是如此。

You want to sort by column, so the problem is that your array is off by 90 degrees.

您想按列排序,所以问题是您的数组偏离了 90 度。

As a first cut, could you just rotate it?

作为第一次剪辑,您可以旋转它吗?

std::string values_by_column[columns][rows];

for (int i = 0; i < rows; i++)
  for (int j = 0; j < columns; j++)
    values_by_column[column][row] = values[row][column]

sort_array(values_by_column[column])

for (int i = 0; i < rows; i++)
  for (int j = 0; j < columns; j++)
    values[row][column] = values_by_column[column][row]

If you know you only want to sort one column at a time, you could optimize this a lot by just extracting the data you want to sort:

如果您知道一次只想对一列进行排序,则可以通过提取要排序的数据来对其进行大量优化:

  string values_to_sort[rows]
  for (int i = 0; i < rows; i++)
    values_to_sort[i] = values[i][column_to_sort]

  sort_array(values_to_sort)

  for (int i = 0; i < rows; i++)
    values[i][column_to_sort] = values_to_sort[i]

In C++ you could play tricks with how to calculate offsets into the array (since you could treat your two-dimensional array as a one-d array) but I'm not sure how to do that in c#.

在 C++ 中,您可以玩弄如何计算数组偏移量的技巧(因为您可以将二维数组视为一维数组),但我不确定如何在 c# 中执行此操作。

回答by David Hall

This code should do what you are after, I haven't generalised it for n by n, but that is straight forward. That said - I agree with MusiGenesis, using another object that is a little better suited to this (especially if you intend to do any sort of binding)

这段代码应该做你所追求的,我没有将它概括为 n × n,但这是直截了当的。也就是说 - 我同意 MusiGenesis,使用另一个更适合这个的对象(特别是如果你打算做任何类型的绑定)

(I found the code here)

(我在这里找到了代码)

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]));
}

回答by Marc Gravell

Can I check - do you mean a rectangular array ([,])or a jagged array ([][])?

我可以检查一下 - 您是指矩形阵列 ( [,]) 还是锯齿状阵列 ( [][])?

It is quite easy to sort a jagged array; I have a discussion on that here. Obviously in this case the Comparison<T>would involve a column instead of sorting by ordinal - but very similar.

对锯齿状数组进行排序非常容易;我在这里有一个讨论。显然在这种情况下Comparison<T>将涉及一列而不是按序排序 - 但非常相似。

Sorting a rectangular array is trickier... I'd probably be tempted to copy the data out into either a rectangular array or a List<T[]>, and sort there, then copy back.

对矩形数组进行排序比较棘手...我可能很想将数据复制到矩形数组或 a 中List<T[]>,然后在那里排序,然后再复制回来。

Here's an example using a jagged array:

这是使用锯齿状数组的示例:

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])); 
} 

For working with a rectangular array... well, here is some code to swap between the two on the fly...

用于处理矩形数组......好吧,这里有一些代码可以在两者之间即时交换......

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];
        }
    }
}

回答by JaredPar

Try this out. The basic strategy is to sort the particular column independently and remember the original row of the entry. The rest of the code will cycle through the sorted column data and swap out the rows in the array. The tricky part is remembing to update the original column as the swap portion will effectively alter the original column.

试试这个。基本策略是对特定列独立排序并记住条目的原始行。其余代码将循环遍历已排序的列数据并换出数组中的行。棘手的部分是记住更新原始列,因为交换部分将有效地改变原始列。


        public class Pair<T> {
            public int Index;
            public T Value;
            public Pair(int i, T v) {
                Index = i;
                Value = v;
            }
        }
        static IEnumerable<Pair<T>> Iterate<T>(this IEnumerable<T> source) {
            int index = 0;
            foreach ( var cur in source) {
                yield return new Pair<T>(index,cur);
                index++;
            }
        }
        static void Sort2d(string[][] source, IComparer comp, int col) {
            var colValues = source.Iterate()
                .Select(x => new Pair<string>(x.Index,source[x.Index][col])).ToList();
            colValues.Sort((l,r) => comp.Compare(l.Value, r.Value));
            var temp = new string[source[0].Length];
            var rest = colValues.Iterate();
            while ( rest.Any() ) {
                var pair = rest.First();
                var cur = pair.Value;
                var i = pair.Index;
                if (i == cur.Index ) {
                    rest = rest.Skip(1);
                    continue;
                }

                Array.Copy(source[i], temp, temp.Length);
                Array.Copy(source[cur.Index], source[i], temp.Length);
                Array.Copy(temp, source[cur.Index], temp.Length);
                rest = rest.Skip(1);
                rest.Where(x => x.Value.Index == i).First().Value.Index = cur.Index;
            }
        }

        public static void Test1() {
            var source = new string[][] 
            {
                new string[]{ "foo", "bar", "4" },
                new string[] { "Hyman", "dog", "1" },
                new string[]{ "boy", "ball", "2" },
                new string[]{ "yellow", "green", "3" }
            };
            Sort2d(source, StringComparer.Ordinal, 2);
        }

回答by Raindog

If you could get the data as a generic tuple when you read it in or retrieved it, it would be a lot easier; then you would just have to write a Sort function that compares the desired column of the tuple, and you have a single dimension array of tuples.

如果您可以在读取或检索数据时将数据作为通用元组获取,那就容易多了;那么你只需要编写一个 Sort 函数来比较元组的所需列,并且你有一个一维的元组数组。

回答by Jeffrey Roughgarden

I like the DataTable approach proposed by MusiGenesis above. The nice thing about it is that you can sort by any valid SQL 'order by' string that uses column names, e.g. "x, y desc, z" for 'order by x, y desc, z'. (FWIW, I could not get it to work using column ordinals, e.g. "3,2,1 " for 'order by 3,2,1') I used only integers, but clearly you could add mixed type data into the DataTable and sort it any which way.

我喜欢上面 MusiGenesis 提出的 DataTable 方法。它的好处是您可以按任何使用列名的有效 SQL 'order by' 字符串进行排序,例如“x, y desc, z”代表“o​​rder by x,y desc, z”。(FWIW,我无法使用列序数使其工作,例如“3,2,1”表示“按 3,2,1”排序)我只使用了整数,但显然您可以将混合类型数据添加到 DataTable 和以任何方式对其进行排序。

In the example below, I first loaded some unsorted integer data into a tblToBeSorted in Sandbox (not shown). With the table and its data already existing, I load it (unsorted) into a 2D integer array, then to a DataTable. The array of DataRows is the sorted version of DataTable. The example is a little odd in that I load my array from the DB and could have sorted it then, but I just wanted to get an unsorted array into C# to use with the DataTable object.

在下面的示例中,我首先将一些未排序的整数数据加载到 Sandbox(未显示)中的 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();
    }
}

回答by Gregory Massov

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();
            }
        }
    }
}

回答by No_Nick777

Can allso look at Array.Sort Method http://msdn.microsoft.com/en-us/library/aa311213(v=vs.71).aspx

也可以看看 Array.Sort Method http://msdn.microsoft.com/en-us/library/aa311213(v=vs.71).aspx

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

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

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

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