寻求一种有效布局日历活动横幅的算法
我正在寻找一种算法来有效地放置全天/多天活动横幅,就像 Outlook 或 Google 日历中的月视图一样。 我有许多带有开始日期和结束日期的事件,按增加的开始(然后结束)日期排序(或您喜欢的任何其他顺序,我正在从数据库表中收集事件)。 我想最大限度地减少平均使用的垂直空间量,因为在活动横幅之后,我需要放置当天的其他活动(这些活动总是在给定日期的横幅之后)。 因此,举例来说,如果我有两个事件,一个 1/10-1/11 和一个 1/11-1/15,我更愿意这样安排它们(每列都是一天):
bbbbb
aa
而不是这样:
aa
bbbbb
因为当我仅添加当天的事件(x、y 和 z)时,我可以这样做(我更喜欢第一个,不想要第二个):
bbbbb vs. aa
aa xyz bbbbb
xyz
但这并不像首先放置较长的事件那么简单,因为对于 1/10-1/11、1/13-1/14 和 1/11-1/13,我想要:
aa cc
bbb
而不是:
bbb
aa cc
因为这将允许事件 x 和 y:
aa cc vs. bbb
xbbby aa cc
x y
当然我更愿意一次性完成此操作。 对于数据结构,我当前使用从日期到列表的映射,其中对于事件的每一天,我将事件添加到相应的列表中。 因此,为期三天的事件会出现在三个列表中,每个列表都位于地图中的某一天下。 这是将结果转换为视觉输出的便捷结构,但我也对其他数据结构持开放态度。 我目前正在使用贪婪算法,我只是按顺序添加每个事件,但这可能会产生不需要的工件,例如:
aa ccc
bbbbb
dd
eeeeeeeeeeeeeeeee
这在大多数“e”事件日中浪费了很多空间。
有任何想法吗?
I'm looking for an algorithm to efficiently place all-day/multi-day event banners, much like the month view in Outlook or Google Calendar. I have a number of events with a begin and end date, ordered by increasing begin (and then end) date (or any other order you please, I'm gathering events from a database table). I would like to minimize the average amount of vertical space used up, because after the event banners I will need to place other events just for that day (these always come after the banners for a given date). So, for example, if I had two events, one 1/10-1/11 and one 1/11-1/15, I would prefer to arrange them like so (each column is a single day):
bbbbb
aa
and not like:
aa
bbbbb
because when I add the events just for the day (x, y, and z), I can do this (I would prefer the first, do not want the second):
bbbbb vs. aa
aa xyz bbbbb
xyz
But it isn't as simple as placing the longer events first, because with 1/10-1/11, 1/13-1/14, and 1/11-1/13, I would want:
aa cc
bbb
as opposed to:
bbb
aa cc
because this would allow for events x and y:
aa cc vs. bbb
xbbby aa cc
x y
And of course I would prefer to do this in one pass. For the data structure, I'm currently using a map from date to list, where for each day of an event I add the event to the corresponding list. So a three-day event appears in three lists,each one under one of the days in the map. This is a convenient structure for transforming the result into visual output, but I'm open to other data structures as well. I'm currently using a greedy algorithm, where I just add each event in order, but that can produce unwanted artifacts like:
aa ccc
bbbbb
dd
eeeeeeeeeeeeeeeee
This wastes a lot of space for most of the "e" event days.
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是一个可能的解决方案的高级草图(使用星期几整数而不是完整的日期)。 该接口:
必须实现才能使用下面
layout
方法中表达的算法。此外,具体类必须实现 Comparable 来创建自然顺序,其中较长的事件先于较短的事件。 (下面的演示的示例实现使用了长度降序、开始日期升序、标签升序的顺序。)
layout
方法采用IEvent
实例的集合并返回一个Map
,它为演示文稿中的每一行分配可以在该行中显示的事件集。每行都是通过选择最长的剩余事件并逐步选择与当前行的先前选择的事件兼容的所有附加事件(按上述顺序)组成的。 效果是所有事件都尽可能向上“漂浮”而不会发生碰撞。
以下演示显示了您问题中的两个场景,以及一组随机创建的事件。
Here is a high-level sketch of one possible solution (using day-of-week integers instead of full-blown dates). This interface:
must be implemented to use the algorithm expressed in the
layout
method below.In addition, the concrete class must implement
Comparable
to create a natural order where longer events precede shorter events. (My sample implementation for the demo below used an order of descending length, then ascending start date, then ascending label.)The
layout
method takes a collection ofIEvent
instances and returns aMap
that assigns to each row in the presentation the set of events that can be shown in that row.Each row is composed by selecting the longest remaining event and progressively selecting all additional events (in the order described above) that are compatible with previously-selected events for the current row. The effect is that all events "float" upward as far as possible without collision.
The following demo shows the two scenarios in your question, along with a randomly-created set of events.
我认为在这种情况下,最好先确保数据组织正确,然后再渲染。 我知道你想要一次通过,但我认为结果会好得多。
例如,将数据组织成给定日期所需的行,并以尽可能最好的方式组织事件,从最长的事件开始(不需要首先显示,但确实需要组织)首先)并向下移动到最短的事件。 这将使您能够相应地渲染输出,而不浪费任何空间,并避免那些“e”事件日。 另外,那么:
or
并不重要,因为
x
和y
始终可以位于bbb
的任一侧,甚至位于aa< 之间/code> 和
cc
我希望这对您有所帮助。
I think in a situation like this, you're much better off making sure your data is organized properly first and then rendering it. I know you want a single pass, but I think the results would be alot better.
For instance, organize the data into the lines you'll need to have for a given day and organize the events the best way possible, starting with the longest events (don't need to be displayed first, but they do need to be organized first) and moving down to the shortest events. This will allow you to render your output accordingly not wasting any space, and avoiding those "e" event days. Additionally, then:
or
won't matter because
x
andy
can always go on either side ofbbb
or even betweenaa
andcc
I hope you find this helpful.