How to create a custom order to sort Java String phone number?

Viewed 447

I have a list of Java String phone number & I need to sort out them based on their operator like - "013..." and "017..." they are both same operator number.

List<String> phoneNumberList = new ArrayList<String>();
phoneNumberList.add("01313445566");
phoneNumberList.add("01414556677");
phoneNumberList.add("01515667788");
phoneNumberList.add("01616778899");
phoneNumberList.add("01717889900");
phoneNumberList.add("01818990011");
phoneNumberList.add("01919001122");

When I print them, they look like -

01313445566
01414556677
01515667788
01616778899
01717889900
01818990011
01919001122

But I want to print them like this using custom order -

01313445566,
01717889900,

01414556677,
01919001122,

01515667788,

01616778899,

01818990011

How may I create a custom order to sort them as per my requirement?

4 Answers

Define your preferred order in a map

Map<String,Integer> order = new HashMap<>();
order.put("013", 1);
order.put("017", 2);
order.put("014", 3);
order.put("019", 4);
order.put("015", 5);
order.put("016", 6);
order.put("018", 7);

Then sort using map order value

list.sort(Comparator.comparing( e -> order.get(e.substring(0,3))))

Update: For java 6

    Collections.sort(list, new Comparator<String>() {
        @Override
        public int compare(String e1, String e2) {
            return order.get(e1.substring(0,3)).compareTo(order.get(e2.substring(0,3)));
        }
    });

Note: It will work if prefix exists in map.

You may try sorting using a custom comparator:

Collections.sort(phoneNumberList, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        boolean s1Match = s1.matches("01[3479].*");
        boolean s2Match = s2.matches("01[3479].*");
        if (s1Match && !s2Match) {
            return -1;
        }
        else if (!s1Match && s2Match) {
            return 1;
        }
        else {
            return s1.compareTo(s2);
        }
    }
});

System.out.println(phoneNumberList);

Using the sample list of 7 numbers you gave above, this prints:

[01313445566, 01414556677, 01717889900, 01919001122, 01515667788, 01616778899,
 01818990011]

The expression String#matches("01[3479].*") will return true for those numbers beginning with 013, 014, 017, and 019. Thus, the custom comparator will place those numbers first, followed by all others. In the case of a tie, the natural string order will be used (which should be fine here, since the numbers all have the same width).

A possible solution can be using object for phone numbers.

Consider the following code:

public class PhoneNumber implements Comparable{

    private int operatorId;
    private String phoneNumber;

    private static final int GRAMEENPHONE = 1;
    private static final int VERIZON = 2;

    public PhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
        char thirdDigit = phoneNumber.charAt(2);
        if(thirdDigit == '7' || thirdDigit == '3') {
            operatorId = GRAMEENPHONE;
        } else if(thirdDigit == '4' || thirdDigit == '9') {
            operatorId = VERIZON;
        } else {
            operatorId = 10; // a default value
        }
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    @Override
    public int compareTo(Object o) {
        PhoneNumber pNumber = (PhoneNumber) o;
        if(this.operatorId == pNumber.operatorId) {
            return this.phoneNumber.compareTo(pNumber.getPhoneNumber());
        }
        return this.operatorId - pNumber.operatorId;
    }
}

The main trick in this code is the operatorId. It is a number that represents different mobile operators/carrier company. This value is used in compareTo() method. And its value is used to determine which operator/carrier company's number should be on top.

And so the code for phone number list should look something like this:

List<PhoneNumber> phoneNumberList = new ArrayList<PhoneNumber>();
phoneNumberList.add(new PhoneNumber("01313445566"));
phoneNumberList.add(new PhoneNumber("01414556677"));
phoneNumberList.add(new PhoneNumber("01515667788"));
phoneNumberList.add(new PhoneNumber("01616778899"));
phoneNumberList.add(new PhoneNumber("01717889900"));
phoneNumberList.add(new PhoneNumber("01818990011"));
phoneNumberList.add(new PhoneNumber("01919001122"));
Collections.sort(phoneNumberList);

Well, you can use RuleBasedCollator to define your own Rules.

String customRules = "<013<017<014<019<015<016<018";

The above rule is decoded as that 013 and 017 are to appear before both 014 when comparing strings.

And then use the rule as below:

RuleBasedCollator myRuleBasedCollator = new RuleBasedCollator(customRules);
Collections.sort(phoneNumberList,myRuleBasedCollator);
phoneNumberList.forEach(System.out::println);

Output:

01313445566
01717889900
01414556677
01919001122
01515667788
01616778899
01818990011
Related