我有一个 csv 解析器,它读取 15+ 百万行(有很多重复项),一旦解析为结构,就需要添加到集合中。每个结构都有属性 Key (int)、A(datetime) 和 B(int)(以及此处不相关的其他属性)。
要求 A:集合需要通过键强制唯一性。
要求 B:在后面的步骤中,我需要按属性 A(时间戳)然后 B(整数)对集合进行排序。
约束结构最终需要按顺序遍历,一个接一个,并引用邻居(LinkedList 在这里提供了最干净的解决方案);此操作的要点是对集合进行分区。请假设这是最早可能发生的分区(即,它不能在解析阶段进行分区)。
我发现 SortedSet 对于要求 A 工作得很好,而且它的性能也相当好,即使 O(log n) 插入比 HashSet<T> 慢得多。的 O(1),尽管我不关心键的排序。 HashSet<T>当集合变大时会陷入困境,这显然是一个已知问题,而 SortedSet<T>没有这个缺点。
问题:当我到达要求 B 的步骤时,对集合进行排序(将 SortedSet<T> 作为 IEnumerable<T> 传递给方法)花费了太多时间(20 多分钟)研磨,全部在内存中,不使用页面文件)。
问题:哪个集合最适合解决这个问题?一个想法是使用两个集合:一个强制执行唯一性(如键的 HashSet<int> 或 SortedSet<int>),第二个 SortedSet<T>在解析阶段处理排序(即,尽可能上游)。但是应用程序已经是内存密集型的,需要页面文件的性能损失是令人望而却步的。
对于按一个特征强制唯一性但按其他不相关特征排序的单个集合,这给我留下了什么选择? SortedSet<T>使用 IComparer<T> (但不是 IComparer<T> 和 IEquitable<T> ),所以如果它依赖 CompareTo 来强制执行唯一性,那么它似乎不符合我的要求。子类化 SortedSet 是可行的方法吗?
编辑:排序代码:
SortedSet<Dto> parsedSet = {stuff};
var sortedLinkedStructs = new LinkedList<Dto>(parsedSet.OrderBy(t => t.Timestamp).ThenBy(i => i.SomeInt));
结构:
public readonly struct Dto: IEquatable<Dto>, IComparer<Dto>, IComparable<Dto>
{
public readonly datetime Timestamp;
public readonly int SomeInt;
public readonly int Key;
ctor(ts, int, key){assigned}
public bool Equals(Dtoother) => this.Key == other.Key;
public override int GetHashCode() => this.Key.GetHashCode();
public int Compare(Dto x, Dto y) => x.Key.CompareTo(y.Key);
public int CompareTo(Dto other) => this.Key.CompareTo(other.Key);
}
最佳答案
这可能不是一个直接的答案,但是:这是我在类似规模的类似系统中成功使用的一种方式。这是用于在 Stack Overflow 上驱动问题列表的“标签引擎”;本质上,我有一个:
struct Question {
// basic members - score, dates, id, etc - no text
}
和基本上一个超大的Question[](实际上我在非托管内存中使用了一个Question*,但那是因为我需要能够出于不相关的原因与一些 GPU 代码共享它)。填充数据只是取出 Question[] 中的连续行。此数据永远不会排序 - 它作为源数据单独保留 - 只需附加(新键)或覆盖(相同键); 在最坏的情况下,如果达到最大容量,我们可能需要重新分配数据并将数据 block 复制到新阵列。
现在,我没有对数据进行排序,而是单独保留一个int[](实际上是int*,原因与之前相同,但是...嗯),其中 int[] 中的每个值都是 Question[ 中实际数据的索引 ]。所以最初它可能是 0, 1, 2, 3, 4, 5, ...(虽然我预先过滤了这个,所以它只包含我想保留的行 - 删除“删除”等)。
使用 或者 修改器并行快速排序(参见 http://stackoverflow.com/questions/1897458/parallel-sort-algorithm )或修改后的“内省(introspection)排序”(如 here ) - 所以在排序结束时,我可能有 0, 3, 1, 5, ...。
现在:为了遍历数据,我只是遍历 int[],并将其用作对 Question 中的实际 数据的查找[]。这最大限度地减少了排序期间的数据移动量,并允许我非常有效地保持多个单独的排序(可能使用不同的预过滤器)。对 15M 数据进行排序仅需几毫秒(每分钟左右发生一次,以便将新问题引入 Stack Overflow,或记录对现有问题的更改)。
为了尽可能快地进行排序,我尝试编写我的排序代码,以便可以用单个整数值表示复合排序,从而实现非常有效的排序(可用于内省(introspection)排序).例如,这里是“最后一个事件日期,然后是问题 ID”排序的代码:
public override bool SupportsNaturallySortableUInt64 => true;
public override unsafe ulong GetNaturallySortableUInt64(Question* question)
{
// compose the data (MSB) and ID (LSB)
var val = Promote(question->LastActivityDate) << 32
| Promote(question->Id);
return ~val; // the same as ulong.MaxValue - val (which reverses order) but much cheaper
}
它的工作原理是将 LastActivityDate 视为 32 位整数,左移 32 位并将其与作为 32 位整数的 Id 组合,这意味着我们可以在单个操作中比较日期和 ID。
或者对于“分数,然后是答案分数,然后是 id”:
public override unsafe ulong GetNaturallySortableUInt64(Question* question)
{
// compose the data
var val = Promote(question->Score) << 48
| Promote(question->AnswerScore) << 32
| Promote(question->Id);
return ~val; // the same as ulong.MaxValue - val (which reverses order) but much cheaper
}
请注意,GetNaturallySortableUInt64 每个元素仅调用一次 - 进入 ulong[] 的工作区域(是的,实际上是 ulong* ) 大小相同,所以最初这两个工作区是这样的:
int[] ulong[]
0 34243478238974
1 12319388173
2 2349245938453
... ...
现在我可以通过只查看 int[] 和 ulong[] 来完成整个排序,这样 ulong[] 矢量以排序顺序结束,int[] 包含要查看的项目的索引。
关于c# - 非常大的集合的效率;迭代和排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48345753/
我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
//1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json
Rails相对较新。我正在尝试调用一个API,它应该向我返回一个唯一的URL。我的应用程序中捆绑了HTTParty。我已经创建了一个UniqueNumberController,并且我已经阅读了几个HTTParty指南,直到我想要什么,但也许我只是有点迷路,真的不知道该怎么做。基本上,我需要做的就是调用API,获取它返回的URL,然后将该URL插入到用户的数据库中。谁能给我指出正确的方向或与我分享一些代码? 最佳答案 假设API为JSON格式并返回如下数据:{"url":"http://example.com/unique-url"
我需要用任何语言编写一个算法,根据3个因素对数组进行排序。我以度假村为例(如Hipmunk)。假设我想去度假。我想要最便宜的地方、最好的评论和最多的景点。但是,显然我找不到在所有3个中都排名第一的方法。Example(assumingthereare20importantattractions):ResortA:$150/night...98/100infavorablereviews...18of20attractionsResortB:$99/night...85/100infavorablereviews...12of20attractionsResortC:$120/night
我这样做(在我看来):#myUserisaUserinActiveRecordwith:has_many:postsmyUser.posts.eachdo|post|end如果用户有10个帖子,这会调用10次数据库吗?这些循环应该像(不那么漂亮)吗?:myPosts=myUser.postsmyPosts.eachdo|post|endHere是我测试的ruby文件的粘贴箱。编辑修改了粘贴箱。这让我想起了Java中的代码for(inti=0;i应该是(除非数组被修改)for(inti=0,len=someExpensiveFunction();i我错过了什么吗?我看到一堆Rails
我正在尝试按Rails相关模型中的字段进行排序。我研究的所有解决方案都没有解决如果相关模型被另一个参数过滤?元素模型classItem相关模型:classPriority我正在使用where子句检索项目:@items=Item.where('company_id=?andapproved=?',@company.id,true).all我需要按相关表格中的“位置”列进行排序。问题在于,在优先级模型中,一个项目可能会被多家公司列出。因此,这些职位取决于他们拥有的company_id。当我显示项目时,它是针对一个公司的,按公司内的职位排序。完成此任务的正确方法是什么?感谢您的帮助。PS-我
我正在构建一个小部件来显示奥运会的奖牌数。我有一个“国家”对象的集合,其中每个对象都有一个“名称”属性,以及奖牌计数的“金”、“银”、“铜”。列表应该排序:1.首先是奖牌总数2.如果奖牌相同,按类型分割(金>银>铜,即2金>1金+1银)3.如果奖牌和类型相同,则按字母顺序子排序我正在用ruby做这件事,但我想语言并不重要。我确实找到了一个解决方案,但如果感觉必须有更优雅的方法来实现它。这是我做的:使用加权奖牌总数创建一个虚拟属性。因此,如果他们有2个金牌和1个银牌,加权总数将为“3.020100”。1金1银1铜为“3.010101”由于我们希望将奖牌数排序为最高的,因此列表按降序排