在 c# 中按 2D 数组行的第一个元素的升序对 2D 数组行进行排序

本文关键字:数组 2D 排序 升序 元素 第一个 中按 | 更新日期: 2023-09-27 18:22:11

我需要按第一个元素的升序对二维数组行进行排序,如示例所示

{{

5,7,6},{2,9,6},{4,8,1}} --> {{2,9,6},{4,8,1},{5,7,6}}

我可以在行中找到最大元素,但我现在不知道如何对行进行排序。

public double[] maxInRow(double[,] n) 
 { 
    double[] result = new double[n.GetLength(0)]; 
    for (int i = 0; i < n.GetLength(0); i++) 
    { 
        double max = 0;
        for (int j = 0; j < n.GetLength(1); j++) 
        { 
        if (max < n[i,j]) 
        { 
            max = n[i,j];
        } 
        } 
    result[i] = max; 
    } 
return result; 
}

你能提出一些建议吗?

提前感谢!

在 c# 中按 2D 数组行的第一个元素的升序对 2D 数组行进行排序

可悲的是,有了这个sintax,你错过了linq的力量,这是.Net framework最好的组成部分之一,你可以试试这个

double[][] x = new double[2][];
x[0] = new double[] { 5, 2, 5 };
x[1] = new double[] { 6, 8, 3 };
x[2] = new double[] { 8, 3, 6 };
var sortedByFisrtVal =  x.OrderBy(y => y[0]);
var sortedBySecondVal = x.OrderBy(y => y[1]);
//trying to guess maybe this is better
var sorted =  x.OrderBy(y => y[0]).ThenBy(y => y[1]).ThenBy(y => y[2]);

如果性能不重要,则可以将 2D 数组转换为行数组,通过 linq 中的 OrderBy 对它们进行排序,提供 Max 作为条件,然后将结果转换回 2D 数组:

        private static T[][] Convert<T>(T[,] source, int firstDim, int secondDim)
        {
            T[][] result = new T[firstDim][];
            for (int i = 0; i < firstDim; i++)
            {
                T[] temp = new T[secondDim];    
                for (int j = 0; j < secondDim; j++)
                {
                    temp[j] = source[i, j];
                }
                result[i] = temp;
            }
            return result;
        }
        private static T[,] ConvertBack<T>(T[][] source, int firstDim, int secondDim)
        {
            var result = new T[firstDim, secondDim];
            for (int i = 0; i < firstDim; i++)
            {
                for (int j = 0; j < secondDim; j++)
                {    
                    result[i, j] = source[i][j];
                }
            }
            return result;
        }
        // usage sample
        double[,] array = { { 5, 7, 6 }, { 2, 9, 6 }, { 4, 8, 1 } };
        int firstDim = array.GetUpperBound(0) + 1;
        int secondDim = array.GetUpperBound(1) + 1;
        double[][] jagged = Convert(array, firstDim, secondDim);
        // actual sort is done here!
        double[][] sorted = jagged.OrderByDescending(row => row.Max()).ToArray();
        double[,] result = ConvertBack(sorted, firstDim, secondDim);

您不需要任何额外的方法。 只需如上所述为 2D 数组实现Sort方法即可。

此排序算法与 1D 数组的排序算法相同,只是您还需要第三个循环来交换行的元素。

public static void Sort(double[,] n)
{
    for (int i = 0; i < n.GetLength(0) - 1; i++)
    {
        for (int j = i; j < n.GetLength(0); j++)
        {
            if (n[i, 0] > n[j, 0]) // sort by ascending by first index of each row
            {
                for (int k = 0; k < n.GetLength(1); k++)
                {
                    var temp = n[i, k];
                    n[i, k] = n[j, k];
                    n[j, k] = temp;
                }
            }
        }
    }
}

你可以这样称呼它。

Sort(your2dArray);

请注意,算法当然会变得非常慢,正如 Alexei Levenkov 所指出的那样。因此,如果性能在这里不重要,请使用它。

如果您使用交错数组而不是 2D 数组,则可以使事情变得更快。此外,linq 支持实现 IEnumerable 的一维数组(因此也是交错数组(,您可以使用 OrderBy 使用快速排序。

2D 数组不是用于排序的,但无论如何,这是您可以做到这一点的方法

public static class MyAlgorithms
{
    public static void SortByFirstColumn<T>(this T[,] array, IComparer<T> comparer = null)
    {
        // Indirect sorting
        var sortIndex = new int[array.GetLength(0)];
        for (int i = 0; i < sortIndex.Length; i++)
            sortIndex[i] = i;
        if (comparer == null) comparer = Comparer<T>.Default;
        Array.Sort(sortIndex, (a, b) => comparer.Compare(array[a, 0], array[b, 0]));
        // Reorder the array using "in situ" algorithm
        var temp = new T[array.GetLength(1)];
        for (int i = 0; i < sortIndex.Length; i++)
        {
            if (sortIndex[i] == i) continue;
            for (int c = 0; c < temp.Length; c++)
                temp[c] = array[i, c];
            int j = i;
            while (true)
            {
                int k = sortIndex[j];
                sortIndex[j] = j;
                if (k == i) break;
                for (int c = 0; c < temp.Length; c++)
                    array[j, c] = array[k, c];
                j = k;
            }
            for (int c = 0; c < temp.Length; c++)
                array[j, c] = temp[c];
        }
    }
}

并按如下方式使用它

double[,] data = { { 5, 7, 6 }, { 2, 9, 6 }, { 4, 8, 1 } };
data.SortByFirstColumn();

此实现不会影响性能。有关其工作原理和一些其他选项的更多说明,请参阅我的回答 如何对大型 2D 数组 C# 进行排序

如果要按第一列排序,然后按第二列排序,然后按第三列排序,依此类推,则可以这样做:

void Main()
{
    var input = new double[,] {{5,7,6},{2,9,6},{2,5,6},{4,8,1}};
    Sort(input);
    // Input is now:
    // {{2,5,6},{2,9,6},{4,8,1},{5,7,6}}
}
public T[,] Sort<T>(T[,] data) where T : IComparable
{
    // Transform to array of arrays.
    var rows = new T[data.GetLength(0)][];
    for (var i = 0; i< data.GetLength(0); ++i)
    {
        rows[i] = new T[data.GetLength(1)];
        for (var j = 0; j < data.GetLength(1); ++j)
            rows[i][j] = data[i, j];
    }
    // Sort rows using a custom array comparer.
    Array.Sort(rows, new ArrayComparer<T>());
    // Write data back to input array.
    for (var i = 0; i< data.GetLength(0); ++i)
        for (var j = 0; j < data.GetLength(1); ++j)
            data[i, j] = rows[i][j];
    return data;
}
public class ArrayComparer<T> : IComparer<T[]> where T : IComparable
{
    public int Compare(T[] x, T[] y)
    {
        var comparer = Comparer<T>.Default;
        // Compare elements as long as they're different.
        for(var i = 0; i < x.Length; ++i)
        {
            var compareResult = comparer.Compare(x[i], y[i]);
            if (compareResult != 0) return compareResult;
        }
        return 0;
    }
}
Array.Sort(double, (a,b)=>{return a[0]-b[0];});