benisntfunny
benisntfunny

Reputation: 103

Sort specific objects in ArrayList without changing others in Java

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

Answers (2)

Sean Patrick Floyd
Sean Patrick Floyd

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

QuantumMechanic
QuantumMechanic

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

Related Questions