3

この多次元配列を昇順または降順に並べ替えようとしています。ただし、列 1 と 2 の間の関係を引き続き一緒にする必要があります (つまり、配列 [0,1] と配列 [0,2] のデータを一緒にするか、何らかの方法で関連付ける必要があります。これは今の私のコード。

int[,] time = new int[5,2]{{0,4},{1,5},{5,10},{3,4},{0,2}};
var sorted = from x in Enumerable.Range(0, time.GetLength(0))
                     from y in Enumerable.Range(0, time.GetLength(1))
                     select new{
                         X = x,
                         Y = y,
                         Value = time[x,y]
                    }into point
                    orderby point.Value descending
                    select point;

これは機能しますが、すべてのデータが分割されます。1列目と2列目の関係を保ちながらソートする方法はありますか?

4

6 に答える 6

5

多次元配列が必要な理由について知りたいです。データを「セル」の2次元コレクションではなく、「行」の1次元コレクションとして扱っていることは明らかです。

単純にList(T)を作成してみませんか。ここで、Tはある種のタプルまたはカスタム構造体です。

表面的には、釘にドライバーを使用しようとしているようです。仕事に適したツールを選択していることを確認してください;)

于 2013-02-08T13:38:45.190 に答える
2

データを多次元配列に格納したいようですが、配列内の各行を個別の原子単位として保持します。さらに、各「ポイント」の比較は、X、次に Y によって行われます。

int[,] time = new int[5, 2] { { 0, 4 }, { 1, 5 }, { 5, 10 }, { 3, 4 }, { 0, 2 } };

var sorted = from x in Enumerable.Range(0, time.GetLength(0))
                     select new Point()
                     {
                         X = time[x,0],
                         Y = time[x,1]
                     } into point
                     orderby point.X ascending , point.Y ascending 
                     select point;

int[,] sortedTime = new int[5,2];
int index = 0;
foreach (var testPoint in sorted)
{
  Point aPoint = (Point) testPoint;
  sortedTime.SetValue(aPoint.X, index, 0);
  sortedTime.SetValue(aPoint.Y, index, 1);

  index++;
}
于 2013-02-05T21:41:45.653 に答える
0

仮定:
1. アイテムをペアにしたままにします。たとえば、{0, 4} を 1 つのペアとして扱い、{1, 5} を別のペアとして扱いたいとします。
2. 期待される昇順の結果は、{{0, 2}、{0, 4}、{1, 5}、{3, 4}、{5, 10}} です。

BTownTKD で提案されているように、多次元配列を使用する代わりに、クラス/構造体を使用してペアを表すことを強くお勧めします。次のいずれかのリスト/配列を使用できます。

  • Tuple<int, int>
  • KeyValuePair<int, int>
  • X と Y の 2 つのプロパティを持つ独自の構造体 IntPair。

これは、並べ替えるだけでなく、さらに操作を簡単に行うのにも役立ちます。非常に具体的な必要がある場合にのみ、多次元配列を使用してください。

Tuple を使用したサンプル コードは次のとおりです。

List<Tuple<int, int>> time = new List<Tuple<int, int>>(){
    new Tuple<int, int>(0,4),
    new Tuple<int, int>(1,5),
    new Tuple<int, int>(5,10),
    new Tuple<int, int>(3,4),
    new Tuple<int, int>(0,2)
};

//Sort Ascending
time.Sort((first, second) =>
    {
        var item1Compare = first.Item1.CompareTo(second.Item1);
        return item1Compare == 0 ? first.Item2.CompareTo(second.Item2) : item1Compare;
    });
//Sort Descending
/*time.Sort((first, second) =>
    {
        var item1Compare = second.Item1.CompareTo(first.Item1);
        return item1Compare == 0 ? second.Item2.CompareTo(first.Item2) : item1Compare;
    });*/
于 2013-02-11T21:46:58.740 に答える
0

物事を考えすぎているようです。たとえば、ポイントをまとめて最初の列で並べ替えたい場合は、2 番目の列を省略しEnumerable.Rangeて値を手動で割り当てます。

int[,] time = new int[5,2]{{0,4},{1,5},{5,10},{3,4},{0,2}};
var sorted = from x in Enumerable.Range(0, time.GetLength(0))
                     select new{
                         X = time[x,0],
                         Y = time[x,1]
                    }into point
                    orderby point.X descending
                    select point;

@Haxx が指摘するように、2 番目の値の順序も重要な場合は, point.Y descending、句に追加するだけです。orderby

于 2013-02-05T19:15:27.647 に答える
0

最速の方法は、次のようなソート アルゴリズムを実装し、 and関数Quicksortのみを使用するように変更することです。次に、これらの関数を多次元配列に実装し、その場で並べ替えることができます。これが実用的な実装です:Compare(i, j)Swap(i, j)

    public static void Main() {
        int[,] time = new int[5, 2] { { 0, 4 }, { 1, 5 }, { 5, 10 }, { 3, 4 }, { 0, 2 } };
        DoSort(time);
    }

    public static void DoSort(int[,] data) {
        Func<int, int, int> comparer = (i, j) => {
            int s1 = Math.Sign(data[i, 0] - data[j, 0]);
            if (s1 != 0) {
                return s1;
            }
            int s2 = Math.Sign(data[i, 1] - data[j, 1]);
            return s2;
        };

        Action<int, int> swapper = (i, j) => {
            var tmp0 = data[i, 0];
            var tmp1 = data[i, 1];
            data[i, 0] = data[j, 0];
            data[i, 1] = data[j, 1];
            data[j, 0] = tmp0;
            data[j, 1] = tmp1;
        };

        int length = data.GetLength(0);
        Quicksort(comparer, swapper, 0, length - 1);
    }

    public static void Quicksort(Func<int, int, int> comparer, Action<int, int> swapper, int left, int right) {
        int i = left, j = right;
        int pivotIdx = (left + right) / 2;

        while (i <= j) {
            while (comparer(i, pivotIdx) < 0) {
                i++;
            }

            while (comparer(j, pivotIdx) > 0) {
                j--;
            }

            if (i <= j) {
                swapper(i, j);
                i++;
                j--;
            }
        }

        // Recursive calls
        if (left < j) {
            Quicksort(comparer, swapper, left, j);
        }

        if (i < right) {
            Quicksort(comparer, swapper, i, right);
        }
    }
}

このコードは配列をその場でソートするため、追加のメモリは必要なく、最終的にソートされた多次元配列が得られます。

于 2013-02-10T20:33:40.647 に答える
0

また、行を常に一緒にしたいので、これを行のコレクションとして扱うべきだと思います。.NET にはそのDataTableための型があります。例えば

        int[,] time = new int[5, 2] { { 0, 4 }, { 1, 5 }, { 15, 10 }, { 3, 4 }, { 0, 2 } };

        DataTable dt = new DataTable();

        dt.Columns.Add("x", System.Type.GetType("System.Int32"));
        dt.Columns.Add("y", System.Type.GetType("System.Int32"));

        for (int i = 0; i < time.Length / 2; i++)
        {
            DataRow dr = dt.NewRow();
            dr[0] = time[i, 0];
            dr[1] = time[i, 1];
            dt.Rows.Add(dr);
        }

        dt.DefaultView.Sort = "x" + " " + "ASC";
        dt = dt.DefaultView.ToTable();

テーブルの列を入力する必要があることに注意してください。それ以外の場合は、アルファベット順に並べ替えられます。数字の 1 つを 15 に変更して、並べ替えが整数で機能することを示しました (15>3、ただしアルファベット順では "15"<"3")。本当に 2D 配列として戻したい場合は、最初の回答を参照してください。

于 2013-02-09T08:11:12.813 に答える