Reputation: 103
Let's say I have an ArrayList of objects with attribute Rank and SubRank. They are passed to me by a web service so I didn't handle the initial ordering. If there is no subrank to be used it is set as -1.
[Rank: 1, SubRank: -1]
[Rank: 2, SubRank: -1]
[Rank: 3, SubRank: 3]
[Rank: 4, SubRank: 2]
[Rank: 5, SubRank: -1]
[Rank: 6, SubRank: 1]
What I need to do is rank order anything with a SubRank only leaving the remaining objects intact so the list ends up looking like:
[Rank: 1, SubRank: -1]
[Rank: 2, SubRank: -1]
[Rank: 6, SubRank: 1]
[Rank: 4, SubRank: 2]
[Rank: 5, SubRank: -1]
[Rank: 3, SubRank: 3]
Restrictions: Java 7, no external libraries
Upvotes: 0
Views: 131
Reputation: 298838
That's not trivial. Probably you'll have to split the list into sublists, according to Rank, then sort these sub-lists by sub-ranks and join them again.
It can be done with only a small amount of pain using a custom Guava Multimap:
public static List<Item> sortBySubRank(List<Item> unsorted) {
// custom multimap that preserves key order, but sorts values
// by supplied comparator
Multimap<Integer, Item> itemsByrank = Multimaps.newMultimap(
new LinkedHashMap<>(),
// collection supplier
() -> new TreeSet<>(
// custom comparator
(Comparator<Item>) (o1, o2) -> Integer.compare(o1.subRank, o2.subRank))
);
// store in multimap
unsorted.forEach((i) -> itemsByrank.put(i.rank, i));
// retrieve sorted values
return ImmutableList.copyOf(itemsByrank.values());
}
OK, just for the fun (and pain) of it, here's a Java 7 version without Guava that basically does the same thing:
public static List<Item> sortBySubRankInJava7(List<Item> unsorted) {
Map<Integer,Set<Item>> map = new LinkedHashMap<>();
Comparator<Item> comparator=new Comparator<Item>() {
@Override public int compare(Item o1, Item o2) {
return Integer.compare(o1.subRank, o2.subRank);
}
};
for (Item item : unsorted) {
if (map.containsKey(item.rank)) {
map.get(item.rank).add(item);
} else {
TreeSet<Item> set = new TreeSet<>(comparator);
set.add(item);
map.put(item.rank, set);
}
}
List<Item> result = new ArrayList<>(unsorted.size());
for (Set<Item> items : map.values()) {
result.addAll(items);
}
return result;
}
Upvotes: 1
Reputation: 13946
Since the OP has mentioned that he is restricted to Java 7 and not adding any libraries...
Make a new List
containing just the items with SubRank > -1
. Then sort that List
. Then iterate down the original list and as you come to an item with SubRank > -1
, replace it with the appropriate item in the sorted list.
List<Item> sortedItems = new ArrayList<>();
for (Item item : items) {
if (item.subRank > -1) {
sortedItems.add(item);
}
}
Collections.sort(sortedItems,
new Comparator<Item>()
{
@Override
public int compare(Item lhs, Item rhs) {
return Integer.compare(lhs.SubRank, rhs.SubRank);
}
});
int sortedIndex = 0;
for (int i; i < items.size(); i++) {
if (items.get(i).subRank > -1) {
items.set(i, sortedItems.get(sortedIndex++));
}
}
Upvotes: 2