我有一组元素/键,我正在从两个不同的配置文件中读取它们。因此,键可能相同,但与每个键相关联的值不同。
我想按排序顺序列出它们。我能做些什么 ?我尝试过SortedList
上课,但它不允许重复键。
我该怎么做?
例如,假设我有 3 个元素,键为 1、2、3。然后我又得到一个具有键 2(但值不同)的元素。然后我希望在现有密钥 2 之后但在 3 之前插入新密钥。如果我再次找到具有密钥 2 的元素,那么它应该在最近添加的密钥 2 之后。
请注意,我使用的是 .NET 2.0
我有一组元素/键,我正在从两个不同的配置文件中读取它们。因此,键可能相同,但与每个键相关联的值不同。
我想按排序顺序列出它们。我能做些什么 ?我尝试过SortedList
上课,但它不允许重复键。
我该怎么做?
例如,假设我有 3 个元素,键为 1、2、3。然后我又得到一个具有键 2(但值不同)的元素。然后我希望在现有密钥 2 之后但在 3 之前插入新密钥。如果我再次找到具有密钥 2 的元素,那么它应该在最近添加的密钥 2 之后。
请注意,我使用的是 .NET 2.0
我更喜欢将 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 或更高版本才能完成此操作。
您需要的是带有自定义IComparer的 Sort 函数。您现在拥有的是使用 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");
}
}
阅读上面的链接以获得更好的信息。
我知道我一开始自己在理解这一点时遇到了一些麻烦,所以如果有任何额外的帮助,请添加评论,我会详细说明
我通过创建一个SortedList<int, List<string>>
. 每当我找到重复键时,我只需将值插入与已存在于 SortedList 对象中的键关联的现有列表中。这样,我可以获得特定键的值列表。
使用您自己的比较器类! 如果排序列表中的键是整数,则可以使用例如此比较器:
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 键和字符串值实例化一个新的 SortedList,请使用:
var mySortedList = new SortedList<int, string>(new DegreeComparer());
如果您并不真正关心具有相同键的元素的顺序,请将所有内容添加到列表中,然后按键排序:
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 中使用 List 初始化程序,但我确定您知道如何使用数据填充列表。
.NET 对稳定排序没有很大的支持(这意味着等效元素在排序时保持它们的相对顺序)。List.BinarySearch
但是,您可以使用和自定义编写自己的 stable-sorted-insert IComparer<T>
(如果键小于或等于目标,则返回 -1,如果大于则返回 +1)。
请注意,这List.Sort
不是一种稳定的排序,因此您要么必须编写自己的稳定快速排序例程,要么只使用插入排序来最初填充集合。
您是否考虑过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' = '一二'
'2' = '两个'
'2' = '两个的另一个值'
'3' = '三'
在 .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]
这个怎么样
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);
}
}
我有一个类似的问题,我正在设计一个类似于国际象棋游戏概念的游戏,你让计算机进行移动。我需要有多个棋子能够移动的可能性,因此我需要有多个棋盘状态。每个 BoardState 都需要根据棋子的位置进行排名。为了论证和简单起见,假设我的游戏是 Noughts and Crosses,而我是 Noughts,而计算机是 Crosses。如果棋盘状态显示连续 3 个 Noughts,那么这对我来说是最好的状态,如果它显示连续 3 个 Crosses,那么这对我来说是最差的状态,对计算机来说是最好的状态。游戏中还有其他状态对其中一种或另一种更有利,而且还有多种状态会导致平局,所以当排名分数相等时,我该如何对其进行排名。
我的比较类:
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 个具有相同 rank-score 的状态都会排在最后,因为它总是有一个更大的分配索引,因此这允许重复。我还可以安全地调用 boardStates.Remove(myCurrentBoardState) ,它也使用比较器,并且比较器必须返回 0 值才能找到要删除的对象。