我正在开发一个小项目,逐步增加链接列表,然后通过队列处理它们。链接可能会两次进入队列,我想跟踪我的进度,以便我可以跳过任何已经处理过的内容。我最多估计大约10k个唯一链接。
对于较大的项目,我会使用数据库,但这对我正在使用的数据量来说似乎有些过分,并且如果我想在运行中保存进度,则可能更喜欢某种形式的内存中解决方案,如果我想保存进度。
哪种数据结构最适合这种需求?
更新:我已经使用哈希来跟踪我已完成处理的链接。这是最有效的方式吗?
def process_link(link)
return if @processed_links[link]
# ... processing logic
@processed_links[link] = Time.now # or other state
end
答案 0 :(得分:1)
如何设置并将链接转换为值对象(而不是引用对象),如Structs。通过创建值对象,Set将能够检测其唯一性。或者,您可以使用哈希并通过PK存储链接。
答案 1 :(得分:1)
数据结构可以是哈希:
current_status = { links: [link3, link4, link5], processed: [link1, link2, link3] }
跟踪进度(百分比):
links_count = current_status[:links].length + current_status[:processed].length
progress = (current_status[:processed].length * 100) / links_count # Will give you percent of progress
处理您的链接:
push
您需要处理current_status[:links]
的任何新链接。 shift
从current_status[:links]
获取要处理的下一个链接。push
将其发送至current_status[:processed]
修改强>
在我看来(并理解你的问题)时,处理链接的逻辑将是:
# Add any new link that needs to be processed to the queue unless it have been processed
def add_link_to_queue(link)
current_status[:to_process].push(link) unless current_status[:processed].include?(link)
end
# Process next link on the queue
def process_next_link
link = current_status[:to_process].shift # return first link on the queue
# ... login process the link
current_status[:processed].push(link)
end
# shift method will not only return but also remove the link from the original array to avoid duplications
答案 2 :(得分:1)
如果您不关心记忆,那么只需使用哈希检查包含;插入和查找时间是O(1)平均情况。序列化很简单(Ruby的Marshal类应该为你处理,或者你可以使用像JSON这样的格式)。 Ruby的Set
是一个类似于数组的对象,后面有一个Hash支持,所以如果您愿意,可以使用它。
但是,如果内存是一个问题,那么Bloom filter这是一个很大的问题!您可以在固定时间内实现集合包含测试,并且过滤器使用的内存大大少于哈希。权衡是Bloom过滤器是概率性的 - 你可以得到错误的包含正面。您可以使用正确的布隆过滤器参数消除大多数误报的概率,但如果重复是异常而不是规则,则可以实现以下内容:
这样可以让您在常见情况下获得非常快速且内存效率高的查找,并且您可以选择接受错误否定的可能性(以保持整个事物的小而快),或者您可以执行集合的验证报告重复时的包含(当你绝对需要时只做昂贵的工作)。
https://github.com/igrigorik/bloomfilter-rb是我过去使用的Bloom过滤器实现;它工作得很好。如果您需要可以跨多个应用实例执行集合成员资格跟踪和测试的东西,还有redis支持的Bloom过滤器。