2

i have a Java Object List

List<MyObject> list = new ArrayList<>();
    list.add(new MyObject("1", "1"));
    list.add(new MyObject("2", "2"));
    list.add(new MyObject("3", "3"));
    list.add(new MyObject("4", "12"));
    list.add(new MyObject("5", "1d2"));

My Objects Are

Public MyObject {
String id;
String myNumber;
...
}

now i want to sort my list by myNumber by only numbers so i want a result:

MyObject("5", "1d3");
MyObject("4", "12");
MyObject("3", "3");
MyObject("2", "2");
MyObject("1", "1");

How can i do this?

with list.sort(Comparator.comparing(MyObject::getMyNumber)); gives me

MyObject("3", "3");
MyObject("2", "2");
MyObject("5", "1d3");
MyObject("4", "12");
MyObject("1", "1");
john
  • 21
  • 3
  • what do you do in case there are multiple "non numbers" like 1d3 and 1e2 – Alan Apr 30 '19 at 07:59
  • Did you accidentally type one extra line in your expected results? Why are there 6 elements in the sorted lists when there is only 5 in the unsorted list? Can you correct it? – Sweeper Apr 30 '19 at 08:00
  • @Sweeper the one OP left out is a duplicate... That raises the question if the elimination of duplicates is part of the taks or not. – deHaar Apr 30 '19 at 08:01
  • pretty sure it was just a typo – Alan Apr 30 '19 at 08:02
  • So `"1d3"` should be smaller than just `"1"`? Why are those strings in the first place and not integers? What do those "numbers" represent? – Thomas Apr 30 '19 at 08:05
  • can you please post your desired outcome too? currently, it seems to be working as expected, since you are comparing strings and not numbers. – Manuel Jain Apr 30 '19 at 08:07
  • his desired outcome is in there @ManuelJain. however, we need an example with multiple text values, in order to understand how those should behave when compared to each other – Alan Apr 30 '19 at 08:08
  • i will ignore all "not number" letters editet my Question :) – john Apr 30 '19 at 08:11
  • @john "ignore all not number letters" means 1d3 will be treated as 13? that doesnt seem to be the case in your desired output – Alan Apr 30 '19 at 08:13
  • Alan, correct. i updated my question, my fail – john Apr 30 '19 at 08:14
  • ahhhhh ok then. this should be easy hold on – Alan Apr 30 '19 at 08:16

6 Answers6

0

I would suggest you write your own compare method inside your object while implementing "Comparable"

something like

public class CompareObject implements Comparable{

String id;
String myNumber;

public CompareObject(String id, String myNumber) {
    this.id = id;
    this.myNumber = myNumber;
}

public int compareTo(CompareObject c) {
    String myNumberOnlyNumbers = "";
    String otherNumberOnlyNumbers = "";
    for(int i = 0; i < myNumber.length(); i++) {
        try {
            myNumberOnlyNumbers += Integer.parseInt(myNumber.charAt(i)+"") + "";
        } catch (NumberFormatException e) {

        }
    }

    for(int i = 0; i < c.myNumber.length(); i++) {
        try {
            otherNumberOnlyNumbers += Integer.parseInt(c.myNumber.charAt(i)+"") + "";
        } catch (NumberFormatException e) {

        }
    }

    return Integer.compare(Integer.parseInt(myNumberOnlyNumbers), Integer.parseInt(otherNumberOnlyNumbers));
}

}

in your case "CompareObject" would be "MyObject"

after that you can do

    List<CompareObject> list = new ArrayList<>();
    list.add(new CompareObject("1", "1"));
    list.add(new CompareObject("2", "2"));
    list.add(new CompareObject("3", "3"));
    list.add(new CompareObject("4", "12"));
    list.add(new CompareObject("5", "1d3"));

    Collections.sort(list, Collections.reverseOrder()); //Collections.reverseOrder() meaning in descending order here

and if i do

    for(int i = 0; i < list.size(); i++) {
        System.out.println(list.get(i).id + " - " + list.get(i).myNumber);
    }

to print the list i get

5 - 1d3
4 - 12
3 - 3
2 - 2
1 - 1
Alan
  • 949
  • 8
  • 26
0

AFAIK there is no java in built solution, but among java developers this is famous as AlphaNumeric sorting and you can find some sample code here.

https://github.com/my-flow/alphanum/blob/master/src/AlphanumComparator.java

hunter
  • 3,963
  • 1
  • 16
  • 19
0
Collections.sort(list, new Comparator<MyObject>() {
        @Override
        public int compare(MyObject o1, MyObject o2) {
            String one = o1.myNumber;
            String two = o2.myNumber;
            if (isNumeric(one) && isNumeric(two)) {
                return Integer.valueOf(two).compareTo(Integer.valueOf(one));
            } else {
                return two.compareTo(one); //add new fuction here to compare strings having alphabets
            }
        }
    });

for(int i=0; i<list.size(); i++){
        System.out.println(list.get(i));
}

isNumeric method:

    public static boolean isNumeric(String str) {
    try {
        Double.parseDouble(str);
        return true;
    } catch(NumberFormatException e){
        return false;
    }
}
0
list.sort(Comparator.comparingLong(myobj ->
                        Long.parseLong(myobj.getMyNumber().replaceAll("\\D", "")
                                                          .replaceFirst("^$", "0"))
                    .reversed());

This assumes you want:

  • to discard all non-digit characters
  • sort numerically descending

(That is what I read from your example: 13, 12, 3, 2, 1.)

The easiest is to provide a long/int function that derives a long from a MyObject.

(The replaceFirst ensures that as value without any digit will yield 0.)

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • Looks good, but i have a litle problem (Java8) - .reverse()) is not found, if i remove it, it works, but asc sorting :< if i add a .reversed() then myobj.getMyNumber().re... not found my methode getMyNumber() ? Oo only toString are avilable – john Apr 30 '19 at 08:59
  • @john it should have been _reverse**d**_; corrected – Joop Eggen Apr 30 '19 at 09:02
  • Like this? list.sort(Comparator.comparingLong(myobj -> Long.parseLong(myobj.getMyNumber().replaceAll("\\D", "") .replaceFirst("^$", "0"))) .reversed()); --- Tells me: Can not resolve Method getMyNumber / Without reversed it works but asc sorted :/ – john Apr 30 '19 at 09:32
  • Negating, `-Long.parseLong(...` would allow to do away with `reversed`. Maybe not at the right `)`. (I have no IDE at this computer.) – Joop Eggen Apr 30 '19 at 10:15
0
List<MyObject> list = new ArrayList<>();
    list.add(new MyObject("1", "1"));
    list.add(new MyObject("2", "2"));
    list.add(new MyObject("3", "3"));
    list.add(new MyObject("4", "12"));
    list.add(new MyObject("5", "1d2"));
    Collections.sort(list, new Comparator<MyObject>() {
        @Override
        public int compare(MyObject o1, MyObject o2) {
            if(Integer.parseInt(o1.getId())<=Integer.parseInt(o2.getId()))
            {
                return 1;
            }else
                return -1;
        }
    });
    for(int i=0;i<list.size();i++)
    {
        System.out.println(list.get(i));
    }
0

I think you problem behind your question shall be 'how to extract numbers from a string', which is well answered in this case. Extract digits from a string in Java

myNumber= myNumber.replaceAll("\\D+","");

And you can create you own comparator to handle the result easily.

Chuck
  • 76
  • 6