在过去的几天里,我试图完成以下关于分析一组对象的任务,我提出的解决方案严重依赖于内存(在某些情况下获得OutOfMemory异常)或采取一段令人难以置信的漫长时间。我现在认为将它发布在这里是一个好主意,因为我没有想法。我将详细解释这个问题,并提供我到目前为止所遵循的逻辑。
情境:
首先,我们有一个对象,我们将其命名为 Individual ,其中包含以下属性:
其次,我们有另一个对象,我们将其命名为 Group ,其定义为: 一组符合以下条件的个人:
该组中的所有个体都有一个日期,彼此之间不超过10天。这意味着如果彼此之间进行比较,所有个人之间在10天之内不会有所不同。
每个物体之间的距离小于Y米。
一个群体可以有N> 1个人,只要每个人符合彼此的条件。 所有个人都存储在数据库中。 所有组也将存储在数据库中。
任务:
现在,考虑一个新人。 系统必须检查是否有新人:
属于现有的一个或多个群组
个人现在与其他个人组成一个或多个新组。
注意:
新个人可以在多个现有群组中,也可以创建多个新群组。
不允许个人子组,例如,如果我们有一个包含个人{A,B,C}的组,则不能存在包含{A,B},{A,C}或{B,C}。
解决方案(处理时间和内存有限)
首先,我们使用与初始条件匹配的所有个人过滤数据库。这将输出一个可枚举的FilteredIndividuals,其中包含我们知道将与新组建立一个Group(of 2)的所有个体。
简而言之,Powerset是一个包含所有可能子集的集合 特定的一套。例如,{A,B,C}的powerset将是: {[empty],A,B,C,AB,AC,BC,ABC}
注意:powerset将输出一组具有2 ^ N组合的新集合,其中N是原始集合的长度。
使用powersets的想法如下:
首先,我们创建FilteredIndividuals列表的powerset。这将在FilteredIndividuals列表中提供所有可能的组合组合。出于分析目的和定义,我们可以省略其中包含少于2个人的所有组合。
我们检查powerset组合中的每个人是否符合彼此的条件。 如果匹配,则表示该组合中的所有个人与新个人组成一个组。然后,为了避免使用子组,我们可以消除包含Checked组合组合的所有子集。我这样做是通过创建Checked组合的powerset,然后从原始组合中删除新的powerset。
此时,我们有一个与形成组的条件匹配的集合列表。
在正式创建组之前,我将DB与包含与新集相同元素的其他现有组进行比较: 如果我找到匹配项,我将删除新创建的集,并将新的个人添加到旧组。 如果我找不到匹配项,则表示它们是新组。所以我将新的个人添加到集合中,最后创建新的组。
当FilteredIndividuals可枚举的个人少于52个时,此解决方案效果很好。之后,抛出内存异常(我知道这是因为数据类型允许的最大大小,但增加这样的大小对于非常大的集合没有帮助。为了您的考虑,最符合条件的个人数量''发现是345)。
注意:我可以访问两个实体的定义。如果有一个新属性可以减少处理时间,我们可以添加它。
我正在使用带有C#的.NET框架,但如果该语言需要更改,我们可以接受这一点,只要我们以后可以将结果转换为我们的主系统可理解的对象。
答案 0 :(得分:3)
集合中的所有个体都有一个日期,彼此之间不超过10天。这意味着如果彼此之间进行比较,所有个人之间在10天之内不会有所不同。 每个物体之间的距离小于Y米。
所以你的问题变成如何在3空间中聚集这些点,partitioning其中X和Y是你的纬度和经度,Z是时间坐标,你的指标是Manhattan distance的适当缩放变体。具体来说,您缩放Z以使10 * Z天等于Y米的最大距离。
一种可能的捷径是使用 divide et impera 并在 buckets 中分类你的点(个人),Y米宽和10天高。你可以将它们的坐标除以Y和10天(你可以使用朱利安日期)。如果个人在桶H {X = 5,Y = 3,Z = 71}中,那么它不能比桶中的任何个体
此时,您可以枚举您的新个人所在的可能群组(如果您使用数据库后端,它们将是SELECT groups.* FROM groups JOIN iig USING (gid) JOIN individuals USING (uid) WHERE individuals.bucketId IN ( @bucketsId )
),并将这些群组与您的个人可能与其他群体形成的群组进行比较(SELECT individuals.id WHERE bucketId IN ( @bucketsId ) AND ((x-@newX)*(x-@newX)+(y-@newY)*(y-@newY)) < @YSquared AND ABS(z - @newZ) < 10)
)。
这种方法效率不高(它取决于数据库,你至少需要一个关于bucketId的索引),但它具有尽可能少使用内存的优势。
在某些带有地理扩展的数据库后端上,您可能希望使用本机纬度和经度函数,而不是隐式转换为米。