我正在编写一个程序来设置各种对象在报告中出现的顺序。
该序列是 Excel 电子表格上的 Y 位置(单元格)。
代码的演示部分如下。
我想要完成的是拥有一个集合,它允许我添加多个对象,并且我可以根据
SortedList list = new SortedList();
Header h = new Header();
h.XPos = 1;
h.name = "Header_1";
list.Add(h.XPos, h);
h = new Header();
h.XPos = 1;
h.name = "Header_2";
list.Add(h.XPos, h);
我知道 SortedList
不允许这样做的顺序获得一个排序的集合,我已经寻找替代品。我不想消除重复项,并且已经尝试过List>
。
谢谢。
I am writing a program to set a sequence in which various objects will appear in report.
The sequence is the Y position (cell) on Excel spreadsheet.
A demo part of code is below.
What I want to accomplish is to have a collection, which will allow me to add multiple objects and I can get a sorted collection based on the sequence
SortedList list = new SortedList();
Header h = new Header();
h.XPos = 1;
h.name = "Header_1";
list.Add(h.XPos, h);
h = new Header();
h.XPos = 1;
h.name = "Header_2";
list.Add(h.XPos, h);
I know that the SortedList
will not allow this and I have been searching for alternate. I don't want to eliminate the duplicates and already tried List<KeyValuePair<int, object>>
.
Thanks.
发布评论
评论(16)
使用您自己的 IComparer!
就像其他一些答案中已经指出的那样,您应该使用您自己的比较器类。为此,我使用一个通用的 IComparer 类,它可以与任何实现 IComparable 的对象一起使用:
在实例化新的 SortedList、SortedDictionary 等时将使用它:
这里 int 是可以重复的键。
Use your own IComparer!
Like already stated in some other answers, you should use your own comparer class. For this sake I use a generic IComparer class, that works with anything that implements IComparable:
You will use it when instancing a new SortedList, SortedDictionary etc:
Here int is the key that can be duplicate.
您可以安全地使用 List<> 。 List 有一个 Sort 方法,其重载接受 IComparer。您可以创建自己的排序器类,如 .这是一个例子:
You can safely use List<> . The List has a Sort method , an overload of which accepts IComparer. You can create your own sorter class as . Here's an example :
我使用以下内容:
我的测试用例:
输出:
I use the following:
My test case:
The output:
问题是数据结构设计不符合需求:同一个XPos需要存储多个Header。因此,
SortedList
不应具有Header
值,而应具有List
值。这是一个简单而小的改变,但它解决了所有问题,并避免像其他建议的解决方案一样产生新问题(参见下面的解释):
请注意,添加一个“有趣”的密钥,例如添加一个随机数或假装 2 个 XPos 具有相同的值值不同会导致许多其他问题。例如,删除特定标头变得困难甚至不可能。
另请注意,如果只需要对少数
List
进行排序,则排序性能比每个
Header
都要好得多。示例:如果有 100 个 XPos,每个 XPos 有 100 个标头,则需要对 10000 个Header
进行排序,而不是 100 个List
。
当然,这种解决方案也有一个缺点:如果有很多 XPos 只有 1 个 Header,则需要创建很多 List,这是一些开销。
更新 22.12.2021
我终于找到时间编写一个名为
SortedBucketCollection
的正确集合,其行为类似于SortedList
。它为每个项目使用 2 个键,第一个与SortedList
键相同,并且许多项目可以具有相同的值。第二个键用于区分具有相同 key1 值的项目。SortedBucketCollection
使用的存储空间比SortedList>
少,因为它为每个“存储桶”使用链表,而不是List
。 >
。使用
SortedBucketCollection
的代码如下所示:
第一个 foreach 的输出:
请注意,该项目不会按照添加顺序进行迭代,而是按其
key1
和key2
排序。有关
SortedBucketCollection
和源代码的详细说明,请参阅我在 CodeProject 上的文章 SortedBucketCollection:一个内存高效的 SortedList,接受具有相同键的多个项目The problem is that the data structure design doesn't match the requirements: It is necessary to store several Headers for the same XPos. Therefore,
SortedList<XPos, value>
should not have a value ofHeader
, but a value ofList<Header>
. It's a simple and small change, but it solves all problems and avoids creating new problems like other suggested solutions (see explanation below):Please note that adding a "funny" key, like adding a random number or pretending that 2 XPos with the same value are different lead to many other problems. For example it becomes difficult or even impossible to remove a particular Header.
Also note that the sorting performance is much better if only few
List<Header>
have to be sorted than everyHeader
. Example: If there are 100 XPos and each has 100 headers, 10000Header
need to be sorted as opposed to 100List<Header>
.Of course, also this solution has a disadvantage: If there are many XPos with only 1 Header, as many Lists need to be created, which is some overhead.
Update 22.12.2021
I finally found time to write a proper collection called
SortedBucketCollection
, which behaves like aSortedList
. It uses 2 keys for each item, the first is the same as aSortedList
key and many items can have for that key the same value. The second key is used to differentiate items sharing the same values for key1.SortedBucketCollection
uses less storage space thanSortedList<int, List<Header>>
, because it uses for each "bucket" a linked list and not aList<>
.Code using
SortedBucketCollection
looks like this:using System;
Output of first foreach:
Note that the item are not iterated in the sequence they were added, but sorted by their
key1
andkey2
.For a detailed description of
SortedBucketCollection
and the source code see my article on CodeProject SortedBucketCollection: A memory efficient SortedList accepting multiple items with the same key最简单的解决方案(与上述所有解决方案相比):使用
SortedSet
,它接受IComparer
类,然后以这种方式实现 Compare 方法:Simplest solution (compared to all of the above): use
SortedSet<T>
, it accepts anIComparer<SortableKey>
class, then implement the Compare method this way:非常感谢您的帮助。在进行更多搜索时,我找到了这个解决方案。 (可在 Stackoverflow.com 的其他问题中找到)
首先,我创建了一个类,它将封装我的类对象(页眉、页脚等),
因此该类应该保存对象,并且每个对象的 PosX 为 int Position
What最终我得到的是排序的“序列”列表。
Thanks a lot for your help. While searching more, I found this solution. (Available in Stackoverflow.com in other question)
First, I created a class which would encapsulate my objects for classes (Headers,Footer etc)
So this class is supposed to hold on the objects, and PosX of each object goes as int Position
What eventually I get is the sorted "Sequence" list.
您是否尝试过允许重复键的
Lookup
http://msdn.microsoft.com/en-us/library/bb460184.aspx
Did you try
Lookup<TKey, TElement>
that will allow duplicate keyshttp://msdn.microsoft.com/en-us/library/bb460184.aspx
您可以使用 SortedList,使用 TKey 的值,以及 TValue 的 int(计数)。
这是一个示例:对单词字母进行排序的函数。
You can use the SortedList, use your value for the TKey, and int (count) for the TValue.
Here's a sample: A function that sorts the letters of a word.
该集合类将维护重复项并插入重复项的排序顺序。诀窍是用唯一值标记项目
因为它们被插入以保持稳定的排序顺序。然后我们把它全部包裹在一个
ICollection 接口。
测试类 标记
结构
lambda 比较器帮助器
This collection class will maintain duplicates and insert sort order for the duplicate. The trick is to tag the items with a unique value
as they are inserted to maintain a stable sort order. Then we wrap it all up in an
ICollection interface.
a test class
The tagging struct
The lambda comparer helper
问题是您使用的东西作为键而不是键(因为它出现多次)。
因此,如果您有真实的坐标,您应该采用
Point
作为 SortedList 的键。或者您创建一个
List
,其中第一个列表索引定义 x 位置,内部列表索引定义 y 位置(如果您愿意,反之亦然)。>
The problem is that you use something as key that isn't a key (cause it occurs multiple times).
So if you have real coordinates you should maybe take the
Point
as the key for your SortedList.Or you create a
List<List<Header>>
where your first list index defines the x-position and the inner list index the y-position (or vice versa if you like).Linq.Lookup 很酷,但如果您的目标只是循环“键”,同时允许它们重复,您可以使用此结构:
然后您可以编写:
HTH
Linq.Lookup is cool and all, but if your target is to simply loop over the "keys" while allowing them to be duplicated you can use this structure:
Then you can write:
HTH
关键(双关语)是创建一个基于 IComparable 的类,该类维护相等性和散列,但如果不相等则永远不会与 0 进行比较。这是可以完成的,并且可以通过一些好处来创建 - 稳定排序(即,首先添加到排序列表的值将保持其位置),并且
ToString()
可以简单地返回实际的键字符串值。这是一个可以解决问题的结构键:
The key (pun intended) to this is to create an
IComparable
-based class that maintains equality and hashing, but never compares to 0 if not equal. This can be done, and can be created with a couple bonuses - stable sorting (that is, values added to the sorted list first will maintain their position), andToString()
can simply return the actual key string value.Here's a struct key that should do the trick:
这就是我解决问题的方法。它应该是线程安全的,但如果不需要,您可以简单地删除
锁
。另请注意,不支持在索引处任意插入,因为这可能会违反排序条件。This is how I solved the problem. It's meant to be thread-safe though you can simply remove the
lock
s if you don't need that. Also note arbitraryInsert
at an index is not supported because that could violate the sort condition.诀窍是用唯一的键来增强你的对象。请参阅以下测试是否通过。我想
让我的点按 X 值排序。只需在我的比较函数中使用裸 Point2D 即可
导致具有相同X值的点被消除。所以我将 Point2D 包装在一个名为的标记类中
已编入索引。
完成这项工作的实用程序是
一个比较器,它采用 lambda
A 标记结构
The trick is to augment your object with a unique key. See the following test which passes. I want
to keep my points sorted by their X value. Just using a naked Point2D in my comparison function will
cause points with the same X value to be eliminated. So I wrap the Point2D in a tagging class called
Indexed.
Utilities to make this work are
A comparer that takes a lambda
A tagging struct
这是我对此的看法。请注意,这里可能有龙,C# 对我来说仍然很新。
用法:
Here's my take on this. Be aware, here might be dragons, C# still still quite new for me.
Usage:
创建一个类并查询列表:
Create a class and query the list: