2010-08-05 69 views
12

我有一套元素/鍵,我從兩個不同的配置文件中讀取。所以鍵可以是相同的,但具有與它們中的每一個相關聯的不同值。如何使用重複鍵對列表進行排序?

我想按排序順序列出它們。我能做什麼 ?我嘗試使用SortedList類,但它不允許重複鍵。

我該怎麼辦?

例如可以說我有3個元素,其中鍵1,2,3。然後我得到一個更多的元素有鍵2(但不同的值)。然後,我希望新密鑰在現有密鑰2之後但在3之前插入。如果我在找到密鑰爲2的元素,那麼它應該在最近添加密鑰2之後進行。

請注意比我使用的要多。 NET 2.0

+0

您是否真的關心具有相同鍵的元素是在現有元素之前還是之後? – BlueMonkMN 2010-08-05 12:43:36

+0

是的。我想維護我的問題中提到的順序 – Learner 2010-08-05 14:27:33

回答

12

我更喜歡使用LINQ對這種類型的事情:

using System.Linq; 

... 

var mySortedList = myList.Orderby(l => l.Key) 
         .ThenBy(l => l.Value); 

foreach (var sortedItem in mySortedList) { 
    //You'd see each item in the order you specified in the loop here. 
} 

注:必須使用.NET 3.5或更高版本,以實現這一目標。

+0

謝謝,但我使用.NET 2.0 – Learner 2010-08-05 12:30:31

+0

Yuck。僅此一點就足以升級。 – 2010-08-05 12:44:55

+1

當使用.net 2.0時,這是不可能的,所以不是他的問題的答案 – Nealv 2010-08-05 12:47:40

1

.NET不支持穩定排序(意思是等價元素在排序時保持它們的相對順序)。但是,您可以使用List.BinarySearch和自定義IComparer<T>(如果密鑰小於或等於目標,則返回-1,如果更大則返回+1)編寫自己的穩定排序插入。

請注意,List.Sort不是一個穩定的排序,所以你要麼必須編寫自己的穩定快速排序例程,要麼只是使用插入排序來初始填充集合。

9

你需要的是一個自定義的排序功能IComparer。當你使用sort時,你現在擁有的是默認的icomparer。這將檢查一個字段值。

當你創建一個自定義的IComparer(你在類中通過實現Icomparable接口來做到這一點)。它的作用是:你的對象檢查你自己排序的列表中的每一個其他對象。

這是通過函數完成的。 (不用擔心VS會在引用你的接口時實現它

public class ThisObjectCLass : IComparable{ 

    public int CompareTo(object obj) { 
      ThisObjectCLass something = obj as ThisObjectCLass ; 
      if (something!= null) 
       if(this.key.CompareTo(object.key) == 0){ 
       //then: 
        if ..... 
       } 
       else if(this.value "is more important then(use some logic here)" something.value){ 
       return 1 
       } 
       else return -1 
      else 
       throw new ArgumentException("I am a dumb little rabid, trying to compare different base classes"); 
     } 
} 

閱讀上面的鏈接以獲取更好的信息。

我知道我有一些麻煩的開始理解這一點我自己,所以對於任何額外的幫助,添加評論,我會闡述

2

如果你真的不關心同鍵的元素序列,通過鍵添加一切列表,然後對它進行排序:

static void Main(string[] args) 
{ 
    List<KeyValuePair<int, MyClass>> sortedList = 
     new List<KeyValuePair<int, MyClass>>() { 
     new KeyValuePair<int, MyClass>(4, new MyClass("four")), 
     new KeyValuePair<int, MyClass>(7, new MyClass("seven")), 
     new KeyValuePair<int, MyClass>(5, new MyClass("five")), 
     new KeyValuePair<int, MyClass>(4, new MyClass("four-b")), 
     new KeyValuePair<int, MyClass>(7, new MyClass("seven-b")) 
     }; 
    sortedList.Sort(Compare); 
} 
static int Compare(KeyValuePair<int, MyClass> a, KeyValuePair<int, MyClass> b) 
{ 
    return a.Key.CompareTo(b.Key); 
} 

如果你真的想後插入的項目是經過這些早期插入,因爲它們插入對它們進行排序:

class Sorter : IComparer<KeyValuePair<int, MyClass>> 
{ 

static void Main(string[] args) 
{ 
    List<KeyValuePair<int, MyClass>> sortedList = new List<KeyValuePair<int, MyClass>>(); 
    Sorter sorter = new Sorter(); 
    foreach (KeyValuePair<int, MyClass> kv in new KeyValuePair<int, MyClass>[] { 
     new KeyValuePair<int, MyClass>(4, new MyClass("four")), 
     new KeyValuePair<int, MyClass>(7, new MyClass("seven")), 
     new KeyValuePair<int, MyClass>(5, new MyClass("five")), 
     new KeyValuePair<int, MyClass>(4, new MyClass("four-b")), 
     new KeyValuePair<int, MyClass>(4, new MyClass("four-c")), 
     new KeyValuePair<int, MyClass>(7, new MyClass("seven-b")) }) 
    { 
     sorter.Insert(sortedList, kv); 
    } 
    for (int i = 0; i < sortedList.Count; i++) 
    { 
     Console.WriteLine(sortedList[i].ToString()); 
    } 
} 
void Insert(List<KeyValuePair<int, MyClass>> sortedList, KeyValuePair<int, MyClass> newItem) 
{ 
    int newIndex = sortedList.BinarySearch(newItem, this); 
    if (newIndex < 0) 
     sortedList.Insert(~newIndex, newItem); 
    else 
    { 
     while (newIndex < sortedList.Count && (sortedList[newIndex].Key == newItem.Key)) 
     newIndex++; 
     sortedList.Insert(newIndex, newItem); 
    } 
} 
#region IComparer<KeyValuePair<int,MyClass>> Members 

public int Compare(KeyValuePair<int, MyClass> x, KeyValuePair<int, MyClass> y) 
{ 
    return x.Key.CompareTo(y.Key); 
} 

#endregion 
} 

或者你可以有一個列表的排序列表:

static void Main(string[] args) 
{ 
    SortedDictionary<int, List<MyClass>> sortedList = new SortedDictionary<int,List<MyClass>>(); 
    foreach (KeyValuePair<int, MyClass> kv in new KeyValuePair<int, MyClass>[] { 
     new KeyValuePair<int, MyClass>(4, new MyClass("four")), 
     new KeyValuePair<int, MyClass>(7, new MyClass("seven")), 
     new KeyValuePair<int, MyClass>(5, new MyClass("five")), 
     new KeyValuePair<int, MyClass>(4, new MyClass("four-b")), 
     new KeyValuePair<int, MyClass>(4, new MyClass("four-c")), 
     new KeyValuePair<int, MyClass>(7, new MyClass("seven-b")) }) 
    { 
     List<MyClass> bucket; 
     if (!sortedList.TryGetValue(kv.Key, out bucket)) 
     sortedList[kv.Key] = bucket = new List<MyClass>(); 
     bucket.Add(kv.Value); 
    } 
    foreach(KeyValuePair<int, List<MyClass>> kv in sortedList) 
    { 
     for (int i = 0; i < kv.Value.Count; i++) 
     Console.WriteLine(kv.Value[i].ToString()); 
    } 
} 

我不知道是否可以使用初始化列表.NET 2.0中像我在上面的第一個例子,但我敢肯定你知道如何用數據填充列表。

0

您是否考慮過NameValueCollection類,因爲它允許您爲每個鍵存儲多個值?你可以例如有以下幾點:

NameValueCollection nvc = new NameValueCollection(); 
    nvc.Add("1", "one"); 
    nvc.Add("2", "two"); 
    nvc.Add("3", "three"); 

    nvc.Add("2", "another value for two"); 
    nvc.Add("1", "one bis"); 

,然後檢索值,你可以有:

for (int i = 0; i < nvc.Count; i++) 
    { 
     if (nvc.GetValues(i).Length > 1) 
     { 
      for (int x = 0; x < nvc.GetValues(i).Length; x++) 
      { 
       Console.WriteLine("'{0}' = '{1}'", nvc.GetKey(i), nvc.GetValues(i).GetValue(x)); 
      } 
     } 
     else 
     { 
      Console.WriteLine("'{0}' = '{1}'", nvc.GetKey(i), nvc.GetValues(i)[0]); 
     } 

    } 

從而使該輸出:

'1'= '一'

'1'='one bis'

'2'='two'

'2'=

'3'= '三'

7

我做到了通過創建 '另一兩值'。每當我找到重複鍵時,只需將該值插入與已存在於SortedList對象中的鍵相關聯的現有列表中。這樣,我可以獲得特定密鑰的值列表。

+2

在C#中沒有實際的排序列表是非常令人難以置信的...... – 2012-06-26 16:42:54

+0

@ BlueRaja-DannyPflughoeft:有一個'SortedList',但它不允許重複的鍵。並注意我的問題是針對.NET 2.0的。無論如何,從.NET 3.5開始,使用Linq中的「Lookup」可以解決同樣的問題。請參閱此鏈接 - http://msdn.microsoft.com/en-us/library/bb460184.aspx。 – Learner 2012-06-27 03:52:32

+3

我知道SortedList和Lookup。但這些都是地圖,而不是列表。在C#中沒有實際的排序列表。有'List.Sort()',但插入然後排序列表是一個'O(n log n)'操作,而它應該只是'O(log n)'或'O(n)'在最壞的情況下。 – 2012-06-27 14:06:29

0

在.NET 2.0,你可以這樣寫:

List<KeyValuePair<string, string>> keyValueList = new List<KeyValuePair<string, string>>(); 

// Simulate your list of key/value pair which key could be duplicate 
keyValueList.Add(new KeyValuePair<string,string>("1","One")); 
keyValueList.Add(new KeyValuePair<string,string>("2","Two")); 
keyValueList.Add(new KeyValuePair<string,string>("3","Three")); 

// Here an entry with duplicate key and new value 
keyValueList.Add(new KeyValuePair<string, string>("2", "NEW TWO")); 

// Your final sorted list with one unique key 
SortedList<string, string> sortedList = new SortedList<string, string>(); 

foreach (KeyValuePair<string, string> s in keyValueList) 
{ 
    // Use the Indexer instead of Add method 
    sortedList[s.Key] = s.Value; 
} 

輸出:

[1, One] 
[2, NEW TWO] 
[3, Three] 
1

這個怎麼樣

 SortedList<string, List<string>> sl = new SortedList<string, List<string>>(); 

     List<string> x = new List<string>(); 

     x.Add("5"); 
     x.Add("1"); 
     x.Add("5"); 
     // use this to load 
     foreach (string z in x) 
     { 
      if (!sl.TryGetValue(z, out x)) 
      { 
       sl.Add(z, new List<string>()); 
      } 

      sl[z].Add("F"+z); 
     } 
     // use this to print 
     foreach (string key in sl.Keys) 
     { 
      Console.Write("key=" + key + Environment.NewLine); 

      foreach (string item in sl[key]) 
      { 
       Console.WriteLine(item); 
      } 
     } 
+0

感謝您查看問題。但'SortedList'是沒有用的。正如在問題本身中提到的,由於某種原因,我將會有重複的鍵,'SortedList'不允許重複的鍵。 – Learner 2011-04-11 04:38:57

+0

@CSharpLearner,這個答案不使用重複鍵。帶有重複鍵的項目會被添加到列表中,因此如果通過鍵遍歷,您將獲得唯一鍵的列表。對於任何鍵,您可能有一個或多個值,因爲每個值本身都是一個列表。這意味着它是List的SortedList值。 – 2015-08-25 17:26:47

5

使用自己的比較器類! 如果您在排序列表鍵是整數,你可以使用例如該比較器:

public class DegreeComparer : IComparer<int> 
{ 
    #region IComparer<int> Members 

    public int Compare(int x, int y) 
    { 
     if (x < y) 
      return -1; 
     else 
      return 1; 
    } 

    #endregion 
} 

要實例化與INT鍵和字符串值的新排序列表使用:

var mySortedList = new SortedList<int, string>(new DegreeComparer()); 
0

我有一個類似的問題,我設計的遊戲類似於國際象棋遊戲的概念,在這個遊戲中你有電腦進行移動。我需要有多個部分能夠採取行動的可能性,因此我需要擁有多個董事會成員國。每個BoardState需要根據棋子的位置進行排名。爲了說服和簡單,說我的遊戲是Noughts and Crosses,我是Noughts,而計算機是Crosses。如果棋盤狀態在連續的Noughts中顯示3,那麼這對我來說是最好的狀態,如果它顯示一排十字,那麼這對我來說是最糟糕的狀態,對電腦來說是最好的狀態。在比賽期間還有其他一些國家對這兩個國家更爲有利,而且還有多國組成了一個Draw,所以如果排名相同,我該如何進行排名。這就是我想出的(如果你不是VB程序員,請提前道歉)。

我的比較器類:

Class ByRankScoreComparer 
    Implements IComparer(Of BoardState) 

    Public Function Compare(ByVal bs1 As BoardState, ByVal bs2 As BoardState) As Integer Implements IComparer(Of BoardState).Compare 
     Dim result As Integer = bs2.RankScore.CompareTo(bs1.RankScore) 'DESCENDING order 
     If result = 0 Then 
      result = bs1.Index.CompareTo(bs2.Index) 
     End If 
     Return result 
    End Function 
End Class 

我聲明:

Dim boardStates As SortedSet(Of BoardState)(New ByRankScoreComparer) 

我局與國家實施:

Class BoardState 
    Private Shared BoardStateIndex As Integer = 0 
    Public ReadOnly Index As Integer 
    ... 
    Public Sub New() 
     BoardStateIndex += 1 
     Index = BoardStateIndex 
    End Sub 
    ... 
End Class 

正如你可以看到RankScores保持在降序和任何2個狀態具有相同的等級分數,後面的狀態會進入最後狀態,因爲它總是很好呃分配索引,因此這允許重複。我也可以安全地調用boardStates.Remove(myCurrentBoardState),它也使用比較器,並且比較器必須返回0值才能找到要刪除的對象。

相關問題