3

I have 3 data fields, let's name them Field 1, Field 2, Field 3

Now let's say I have these values:

Field 1  Field 2  Field 3
    1       3        4
    2       3        3
    3       3        5
    4       2        5

How do I write a comparator that sorts such that I will have Field 1 in ascending order, and if Field 2is equal, then it will sort Field 3 by descending order. The result should be this:

Field 1  Field 2  Field 3
    1       3        5
    2       3        4
    3       3        3
    4       2        5

I am probably going to need to swap values around, but that is okay.

4
  • What have you attempted so far? Commented Jan 18, 2016 at 22:47
  • I have tried checking if Field 2 is equal for two objects, and if they are, swap the values. Based on Field 1 The problem is, the sorting algorithm used by the library doesn't seem to compare everything so I have some values that are still unsorted. Commented Jan 18, 2016 at 22:50
  • What kind of sorting library are you using? Is it accepting the standard Java Comparator? Commented Jan 18, 2016 at 22:53
  • Yes I am just using the java utils library and it is accepting the standard Comparator Commented Jan 18, 2016 at 23:12

3 Answers 3

3

EDIT: I have misunderstood the problem. This solution sorts on Field 1 followed by Field 2 followed by Field 3. This is not what OP is looking for.

I suspect that you have a Java object that contains these three fields. I'll assume that they can be accessed via getters. I will also assume that your objects are stored in a List of some kind.

You have not specified which version of Java you are using so I'll go with a Java 8 solution. This could be used with earlier version of Java but it would be more verbose.

    List<MyObject> myObjects = Arrays.asList(new MyObject(1, 2, 3),
                                             new MyObject(0, 1, 2),
                                             new MyObject(1, 1, 1),
                                             new MyObject(1, 1, 0),
                                             new MyObject(1, 2, 1));
    List<MyObject> sortedList = myObjects.stream()
                                         .sorted(Comparator.comparing(MyObject::getField1)
                                                           .thenComparing(MyObject::getField2)
                                                           .thenComparing(MyObject::getField3))
                                         .collect(Collectors.toList());

    System.out.println(sortedList);

This program outputs

[0-1-2, 1-1-0, 1-1-1, 1-2-1, 1-2-3]

This solution uses Java 8 Stream API with the method sorted() which allows you to easily sort a Stream. The sort is achieved by using a Comparator which is a simple class that can determine which of two instances is "larger" than another.

Creating a Comparator that compares instances based on a field is very simple thanks to the Comparator.comparing() method. Comparing based on multiple fields is a simple process of chaining the returned Comparator using .thenComparing().

Java 8 method references are used to refer to field's getters.

Full code:

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

public class MyObject
{
    private int field1;
    private int field2;
    private int field3;

    public MyObject(int field1,
                    int field2,
                    int field3)
    {
        this.field1 = field1;
        this.field2 = field2;
        this.field3 = field3;
    }

    public int getField1()
    {
        return field1;
    }

    public int getField2()
    {
        return field2;
    }

    public int getField3()
    {
        return field3;
    }

    @Override
    public String toString()
    {
        return field1 + "-" + field2 + "-" + field3;
    }

    public static void main(String[] args)
    {
        List<MyObject> myObjects = Arrays.asList(new MyObject(1, 2, 3),
                                                 new MyObject(0, 1, 2),
                                                 new MyObject(1, 1, 1),
                                                 new MyObject(1, 1, 0),
                                                 new MyObject(1, 2, 1));
        List<MyObject> sortedList = myObjects.stream()
                                             .sorted(Comparator.comparing(MyObject::getField1)
                                                               .thenComparing(MyObject::getField2)
                                                               .thenComparing(MyObject::getField3))
                                             .collect(Collectors.toList());

        System.out.println(sortedList);
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

I am using Java 7, sorry I forgot to specify
Simply create a Comparator<MyObject> that compares based on field1 and if they are equal, compares based on field2 and if they are equal compares based on field3. This answer you be a great starting point: stackoverflow.com/questions/2839137/…
But Field 1 doesn't have to be equal. Field 1 is the main sorting priority. Only if after we sorted by Field 1 and we see that Field 2 is equal, we should sort those objects equal in Field 2s by descending Field 3
Ok then, I have misunderstood your problem. I will edit my answer.
1

I would do this in two parts. Part 1 would be to sort based on Field 1.

Part 2 would involve creating a map (HashMap) with the values of Field 2 as the keys mapping to a binary heap (PriorityQueue) of the Field 3 values, sorted in reverse order. I would then iterate though the original array and replace Field 3 with the element take form the top of the Field 2 heap.

Comments

0

Ok after reading your reply to the earlier answer, I think you are after a two pass approach. First you want to sort the list of objects by the first field. Then you want to go back through the collection and if two items have the same field two, we sort them by field three.

So this is easiest to do by sorting the collection twice using two different comparators, the first to sort by field one:

@Override
public int compare(MyObject o1, MyObject o2) {
    return Integer.compare(o1.getFieldOne(), o2.getFieldOne());
}

And the second that sorts by field three only when field two is equal

    @Override
    public int compare(MyObject o1, MyObject o2) {
        int secondFieldComparison = Integer.compare(o1.getFieldTwo(), o2.getFieldTwo());
        if (secondFieldComparison == 0) {
            return Integer.compare(o1.getFieldThree(), o2.getFieldThree());
        } else {
            return 0;
        }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.