我有一套元素/键,我从两个不同的配置文件中读取。所以键可以是相同的,但具有与它们中的每一个相关联的不同值。如何使用重复键对列表进行排序?
我想按排序顺序列出它们。我能做什么 ?我尝试使用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或更高版本,以实现这一目标。
.NET不支持稳定排序(意思是等价元素在排序时保持它们的相对顺序)。但是,您可以使用List.BinarySearch
和自定义IComparer<T>
(如果密钥小于或等于目标,则返回-1,如果更大则返回+1)编写自己的稳定排序插入。
请注意,List.Sort
不是一个稳定的排序,所以你要么必须编写自己的稳定快速排序例程,要么只是使用插入排序来初始填充集合。
你需要的是一个自定义的排序功能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");
}
}
阅读上面的链接以获取更好的信息。
我知道我有一些麻烦的开始理解这一点我自己,所以对于任何额外的帮助,添加评论,我会阐述
如果你真的不关心同键的元素序列,通过键添加一切列表,然后对它进行排序:
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中像我在上面的第一个例子,但我敢肯定你知道如何用数据填充列表。
您是否考虑过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'= '三'
我做到了通过创建 '另一两值'。每当我找到重复键时,只需将该值插入与已存在于SortedList对象中的键相关联的现有列表中。这样,我可以获得特定密钥的值列表。
在C#中没有实际的排序列表是非常令人难以置信的...... – 2012-06-26 16:42:54
@ 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
我知道SortedList和Lookup。但这些都是地图,而不是列表。在C#中没有实际的排序列表。有'List.Sort()',但插入然后排序列表是一个'O(n log n)'操作,而它应该只是'O(log n)'或'O(n)'在最坏的情况下。 – 2012-06-27 14:06:29
在.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);
}
}
感谢您查看问题。但'SortedList'是没有用的。正如在问题本身中提到的,由于某种原因,我将会有重复的键,'SortedList'不允许重复的键。 – Learner 2011-04-11 04:38:57
@CSharpLearner,这个答案不使用重复键。带有重复键的项目会被添加到列表中,因此如果通过键遍历,您将获得唯一键的列表。对于任何键,您可能有一个或多个值,因为每个值本身都是一个列表。这意味着它是List的SortedList值。 – 2015-08-25 17:26:47
使用自己的比较器类! 如果您在排序列表键是整数,你可以使用例如该比较器:
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());
我有一个类似的问题,我设计的游戏类似于国际象棋游戏的概念,在这个游戏中你有电脑进行移动。我需要有多个部分能够采取行动的可能性,因此我需要拥有多个董事会成员国。每个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值才能找到要删除的对象。
您是否真的关心具有相同键的元素是在现有元素之前还是之后? – BlueMonkMN 2010-08-05 12:43:36
是的。我想维护我的问题中提到的顺序 – Learner 2010-08-05 14:27:33