I have a Collection (unordered) of objects with an id property, and an (ordered) List of ids. The id list is not sorted. I\'d like to crea
Read the List of ID's, copying the Collection into a new List in the ID List order.
You can:
With the first solution you have to modify your object, with the second one you have to create another class but you can leave your object unmodified.
<T>
is your object class.
It sounds like your id list has its own order; you're not just using the natural order, right?
Here's the Guava solution:
Ordering.explicit(idList)
// constructs a "fluent Comparator" that compares elements in the
// explicitly specified order
.onResultOf(new Function<MyObject, Id>() {
public Id apply(MyObject o) { return o.getId(); }
}) // make this a Comparator<MyObject> that compares on IDs
.sortedCopy(myObjects); // get the sorted copy of the collection
That's it. Nothing to it. (Disclosure: I contribute to Guava.)
Alternately, if you know IDs are unique, it might just say
Map<Id, MyObject> objectsById =
Maps.uniqueIndex(myObjects, GET_ID_FUNCTION); // defined elsewhere
List<MyObject> sortedObjects = Lists.newArrayList();
for (Id id : sortedIds)
sortedObjects.add(objectsById.get(id));
If your unordered input is no more specific than Collection and your List of ids is in an arbitrary order (not decreasing numerically or something like that), your simplest and quite performant approach is probably this. The cost is linear, O(m+n) where m is the number of ids in your initially sorted list and n is the number of values to sort.
Map<IDType, ValueType> keyed = new HashMap<IDType, ValueType>();
for (ValueType value : unsortedCollection) {
keyed.put(value.getId(), value);
}
List<ValueType> sorted = new ArrayList<ValueType>();
for (IDType id : sortedIds) {
ValueType value = keyed.get(id);
if (value != null) {
sorted.add(value);
}
}
Sounds like you have a given order you want, that may or may not be numerically ascending / descending?
I would recommend making your own Predicate below.
org.apache.commons.collections.CollectionUtils.find(java.util.Collection collection,
Predicate predicate);
and loop over your specific ordering finding each actual object in the unordered list. N^2 solution
and a creative use of java.util.collections.sort(List list, Comparator c)
, a org.apache.find(), and java.util.collections.swap(List list, int i, int j)
you may get away from n^2
Create a class that implements Comparable. In that class, do the sorting according to your ordered list of ids. Then define a TreeSet based on the Comparable class. A greatly simplified example is shown below.
e.g.
public class MyObject implements Comparable<MyObject> {
private Integer id;
// a map of IDs to how they are ordered.
private static Map<Integer, Integer> idOrder = null;
public MyObject(Integer id) {
setId(id);
if (idOrder == null) {
idOrder = new HashMap<Integer, Integer>();
idOrder.put(17, 1);
idOrder.put(27, 2);
idOrder.put(12, 3);
idOrder.put(14, 4);
}
}
public int getId() {
return (this.id);
}
public void setId(int id) {
this.id = id;
}
public int compareTo(MyObject anotherThing) {
return (idOrder.get(this.getId()).compareTo(idOrder.get(anotherThing.getId())));
}
}
Then, define and populate your set like so:
private Set<MyObject> mySet = new TreeSet<MyObject>;
mySet.add(new MyObject(12));
mySet.add(new MyObject(17));
When you do a mySet.add(), it will automatically sort according to your MySort class. If you iterate over the resulting TreeSet, the "17" entry will come before the "12" entry.