캘린더 이벤트 배너를 효율적으로 레이아웃에 대한 알고리즘을 찾고 있습니다

StackOverflow https://stackoverflow.com/questions/400288

  •  03-07-2019
  •  | 
  •  

문제

Outlook 또는 Google Calendar의 Month View와 마찬가지로 하루 종일/멀티 며칠 이벤트 배너를 효율적으로 배치 할 수있는 알고리즘을 찾고 있습니다. 시작 및 종료 날짜가있는 여러 이벤트가 있으며, 시작 (및 종료) 날짜를 늘려서 주문합니다 (또는 다른 주문이 제기하는 경우 데이터베이스 테이블에서 이벤트를 수집하고 있습니다). 이벤트 배너 후에는 그 날을 위해 다른 이벤트를 배치해야하기 때문에 사용한 수직 공간의 평균 양을 최소화하고 싶습니다 (이것은 항상 주어진 날짜에 배너를 따라 온다). 예를 들어, 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

물론 나는 이것을 한 번의 패스로 선호합니다. 데이터 구조의 경우 현재 날짜부터 목록까지지도를 사용하고 있는데, 여기서 매일 이벤트를 해당 목록에 추가합니다. 따라서 3 일간의 이벤트가 3 개의 목록에 나타납니다. 각 이벤트는 각각지도에서 하루 중 하나 아래에 있습니다. 이것은 결과를 시각적 출력으로 변환하기위한 편리한 구조이지만 다른 데이터 구조에도 열려 있습니다. 나는 현재 욕심 많은 알고리즘을 사용하고 있는데, 여기서 각 이벤트를 순서대로 추가하지만 다음과 같은 원치 않는 아티팩트를 생성 할 수 있습니다.

aa ccc          
 bbbbb
    dd
     eeeeeeeeeeeeeeeee

이것은 낭비 a 많은 대부분의 "E"이벤트 일을위한 공간.

어떤 아이디어?

도움이 되었습니까?

해결책

다음은 하나의 가능한 솔루션의 높은 수준의 스케치입니다 (완전한 날짜 대신 주일 정수 사용). 이 인터페이스 :

public interface IEvent {

    public abstract int getFirst();  // first day of event
    public abstract int getLast();   // last day of event
    public abstract int getLength(); // total number of days
    public abstract char getLabel(); // one-char identifier

    // true if this and that have NO days in common
    public abstract boolean isCompatible(IEvent that);

    // true if this is is compatible with all events
    public abstract boolean isCompatibleWith(Collection<IEvent> events);

}

표현 된 알고리즘을 사용하려면 구현해야합니다. layout 아래 방법.

또한 콘크리트 클래스는 구현해야합니다 Comparable 더 긴 이벤트가 더 짧은 이벤트보다 우선하는 자연 순서를 만듭니다. (아래 데모의 샘플 구현은 하강 길이의 순서를 사용한 다음 시작 날짜를 올린 다음 오름차순 레이블을 사용했습니다.)

그만큼 layout 메소드는 수집을 취합니다 IEvent 인스턴스와 반환 a Map 프레젠테이션에서 각 행에 해당 행에 표시 될 수있는 이벤트 세트를 할당합니다.

public Map<Integer,Set<IEvent>> layout(Collection<IEvent> events) {
    Set<IEvent> remainingEvents = new TreeSet<IEvent>(events);
    Map<Integer,Set<IEvent>> result = new TreeMap<Integer,Set<IEvent>>();
    int day = 0;
    while (0 < remainingEvents.size()) {
        Set<IEvent> dayEvents = new TreeSet<IEvent>();
        for(IEvent e : remainingEvents) {
            if (e.isCompatibleWith(dayEvents)) {
                dayEvents.add(e);
            }
        }
        remainingEvents.removeAll(dayEvents);
        result.put(day, dayEvents);
        ++day;
    }
    return result;
}

각 행은 가장 긴 남은 이벤트를 선택하고 현재 행에 이전에 선택한 이벤트와 호환되는 모든 추가 이벤트 (위의 순서로)를 점차적으로 선택하여 구성됩니다. 그 효과는 모든 이벤트가 충돌없이 가능한 한 더 위로 "플로트"한다는 것입니다.

다음 데모는 무작위로 만들어진 이벤트 세트와 함께 두 가지 시나리오를 보여줍니다.

Event collection:
    x(1):4
    b(5):2..6
    y(1):5
    a(2):1..2
    z(1):6
Result of layout:
    0 -> {b(5):2..6}
    1 -> {a(2):1..2, x(1):4, y(1):5, z(1):6}
Visual presentation:
      bbbbb
     aa xyz

Event collection:
    x(1):1
    b(3):2..4
    a(2):1..2
    c(2):4..5
    y(1):5
Result of layout:
    0 -> {b(3):2..4, x(1):1, y(1):5}
    1 -> {a(2):1..2, c(2):4..5}
Visual presentation:
     xbbby 
     aa cc 

Event collection:
    f(2):1..2
    h(2):1..2
    d(4):1..4
    e(4):2..5
    c(1):6
    a(2):5..6
    g(4):2..5
    b(2):0..1
Result of layout:
    0 -> {d(4):1..4, a(2):5..6}
    1 -> {e(4):2..5, b(2):0..1, c(1):6}
    2 -> {g(4):2..5}
    3 -> {f(2):1..2}
    4 -> {h(2):1..2}
Visual presentation:
     ddddaa
    bbeeeec
      gggg 
     ff    
     hh    

다른 팁

이런 상황에서 데이터가 먼저 올바르게 구성되어 있는지 확인한 다음 렌더링하는 것이 훨씬 좋습니다. 나는 당신이 단일 패스를 원한다는 것을 알고 있지만 결과가 더 나을 것이라고 생각합니다.

예를 들어, 주어진 날에 필요한 라인으로 데이터를 구성하고 가장 긴 이벤트부터 시작하여 가능한 가장 좋은 방법으로 이벤트를 구성하십시오 (먼저 표시 할 필요는 없지만 구성해야합니다. 먼저) 가장 짧은 이벤트로 내려갑니다. 이렇게하면 공간을 낭비하지 않고 "E"이벤트 일을 피할 수 있습니다. 또한 다음과 같이 :

 bbb
aa cc

또는

aa cc
 bbb

때문에 중요하지 않습니다 x 그리고 y 항상 양쪽에 갈 수 있습니다 bbb 또는 사이에도 aa 그리고 cc

도움이되기를 바랍니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top