Theodor
Theodor

Reputation: 165

Sorting algorithm which alternates equal items

What would be a good (simple) algorithm/method for this sorting situation:

I have an array of items where each item consists of 2 fields: (ID, Timestamp)

There are many pairs of items with the same ID's.

I want to sort the array such that the items are alternating among ID's as much as possible, starting from the item with the earliest Timestamp.

For example, with this input:

(1, 15:00)
(1, 15:05)
(1, 15:10)
(2, 15:15)
(2, 15:20)
(2, 15:25)
(3, 15:30)
(4, 15:35)
(3, 15:40)

I would get this output:

(1, 15:00)
(2, 15:15)
(3, 15:30)
(4, 15:35)
(1, 15:05)
(2, 15:20)
(3, 15:40)
(1, 15:10)
(2, 15:25)

I'm primarily looking for a algorithm which is conceptually simple, but of course it's nice if it's performant.

Right now the best I can think of is something like:

  1. Init/create temporary array T
  2. From the array A: Get item X with earliest Timestamp where ID is not in T
  3. Add X to result set R, add X.ID to T, pop X from A
  4. As long as X exists, repeat step 2-3, otherwise restart at step 1
  5. Quit when A is empty

Upvotes: 1

Views: 98

Answers (1)

jacobm
jacobm

Reputation: 14035

  1. Put all items in a sorted multimap that sorts first by ID, then by time. (For instance you can implement this with your favorite sorted associative container keyed by ID, where each value in the sorted container is itself another sorted container that holds all time values.
  2. While there are still any elements in this multimap: for each key in ascending order, remove the first element with that key and add it to the result.

When you are done, if I've understood the problem correctly, the result will be in the order you want.

Here's an example in Java, using Guava TreeMultimaps (untested):

TreeMultimap<Id, Timestamp> map = new TreeMultimap<Id, Timestamp>();
for (/* ... every item ... */) {
  map.put(item.getId(), item.getTimestamp());
}

List<Entry> outputList = new ArrayList<Entry>();
while (!map.isEmpty()) {
  for (Id key : map.keySet()) {
    Timestamp value = map.get(key).first();
    outputList.add(new Entry(key, value));
    map.remove(key, value);
  }
}
return outputList;

Upvotes: 2

Related Questions