2008-10-24 230 views
30

我有一個二維數組(字符串)組成我的數據表(行和列)。我想按任何列對這個數組進行排序。我試圖找到一個在C#中執行此操作的算法,但尚未成功。如何在C#中對二維數組進行排序?

任何幫助表示讚賞。

回答

20

將您的二維字符串數組加載到實際的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"); 

你也可以編寫你自己的方法來排序一個二維數組。這兩種方法都是有用的學習經驗,但DataTable方法將幫助您開始學習更好的方式來處理C#應用程序中的數據表。

6

Here是從吉姆米契爾在InformIT的,處理分揀矩形和鋸齒狀多維數組存檔的製品。

+0

該示例實際上並未對數組進行排序; LINQ將產生一個排序的序列,但只有當你捕獲結果...它不排序現有的數組。這可能只是:string [] names = {「Smith」,「Snyder」,「Baker」,「Jonson」,「Ballmer」}; Array.Sort(names); – 2008-10-24 03:46:55

+0

我可以看到你在說什麼 - 我會刪除這個有缺陷的例子,但留在鏈接到排序文章。 PS - 謝謝你告訴我投票的理由。你沒有經常看到,但它真的是建設性的! – 2008-10-24 03:58:23

+1

因爲您已經修復了這個問題,所以我刪除了回調票; -p – 2008-10-24 04:06:50

0

所以你的陣列的結構是這樣的(我在僞要討論,因爲我的C#-FU弱,但我希望你我在說什麼的要點)

string values[rows][columns] 

所以value[1][3]在第1行,第3列

你想列進行排序的值,所以這個問題是,你的陣列是關閉的90度。

作爲第一次切割,你可以旋轉它嗎?

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] 

在C++中,你可以玩花招:

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] 

如果你知道你只需要一列在同一時間進行排序,你可以通過只提取數據要排序優化這個有很多以及如何計算數組中的偏移量(因爲您可以將二維數組視爲一維數組),但我不確定如何在c#中執行此操作。

1

這段代碼應該做你以後的事,我沒有將它推廣到n乘n,但那是直截了當的。儘管如此 - 我同意MusiGenesis,使用另一個對象,它是一個小更適合這個(特別是如果你打算做任何形式的結合)

(我發現的代碼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])); 
} 
35

燦我檢查 - 你是指矩形陣列([,])還是鋸齒陣列([][])?

這是很容易排序一個鋸齒狀的數組;我有一個關於here的討論。顯然,在這種情況下,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]; 
     } 
    } 
} 
0

試試看。基本策略是獨立排序特定列並記住條目的原始行。其餘代碼將循環訪問已排序的列數據並交換數組中的行。棘手的部分是記住更新原始列,因爲交換部分將有效地改變原始列。


     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[] { "jack", "dog", "1" }, 
       new string[]{ "boy", "ball", "2" }, 
       new string[]{ "yellow", "green", "3" } 
      }; 
      Sort2d(source, StringComparer.Ordinal, 2); 
     } 
0

如果您在讀取或檢索數據時可以將數據作爲通用元組來獲取,那將會容易得多;那麼你只需編寫一個Sort函數來比較元組的所需列,並且你有一個元組的單維數組。

0

我喜歡上面MusiGenesis提出的DataTable方法。好的一點是,你可以通過使用列名的字符串來排序任何有效的SQL'order by 「x,y desc,z」表示'按x,y desc,z'排序。 (FWIW,我無法使用列順序來工作,例如「3,2,1」爲'按順序排列3,2,1')我只使用整數,但顯然可以將混合類型數據添加到DataTable中,以任何方式對其進行排序。

在下面的例子中,我首先將一些未排序的整數數據加載到sandbox中的tblToBeSorted(未顯示)。在表和它的數據已經存在的情況下,我將它加載到一個2D整數數組中,然後加載到一個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(); 
    } 
} 
1
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(); 
      } 
     } 
    } 
} 
0

這是一個老問題,但在這裏就是我剛剛建立了基於the article from Jim Mischel at InformItDoug L.

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

我知道它的晚了,但這裏是我的想法,你可能想考慮。

例如這是陣列

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

,並要通過coloumn 2號,將其轉化,那麼你已經整理由所需coloumn陣列

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

祝賀。您可以編輯它以使其與其他數據類型配合使用

相關問題