-3

i am trying to sort an list array that has Strings that contain Integers and letters but when i do it the regular way i get some wierd output: relevant code:

List<String> words = new ArrayList<>();  
words.add("9 hello");
words.add("98 food");
words.add("105 cat");
words.add("2514 human");
words.add("3 pencil");
words.sort(Comparator.reverseOrder());

i am expecting :

"2514 human"
"105 cat"
"98 food"
"9 hello"
"3 pencil"

but i am getting something like this:

"98 food"
"9 hello"
"3 pencil"
"2514 human"
"105 cat"

any suggestions?

BLH-Maxx
  • 39
  • 2
  • 11
  • 2
    why exactly would you expect that outcome? you asked for a reversed alphabetical order, which seems exactly what you get – Stultuske Feb 07 '19 at 10:33
  • Why `2514 human` should be before `105 cat`? – nortontgueno Feb 07 '19 at 10:34
  • 1
    You are sorting text **lexicographical**. You are not interpreting the numbers. `9...` is higher than `2...` no matter what comes after. You need to interpret the numbers as actual numbers instead of text to sort this in the way you want. – Zabuzard Feb 07 '19 at 10:35
  • 2
    My guess, you'll need a composite object and do a reverse sort not on the word, but on the numerical value – Stultuske Feb 07 '19 at 10:35
  • 2
    your values are not an integer, it is compared as a string – Ruslan Feb 07 '19 at 10:35
  • @BLM-Maxx you need to sort descending based on the count – Ashok Kumar N Feb 07 '19 at 10:43
  • As a note to all of you that are not reading the full context. I am reviving an order of just the first 2 digits and has Notting to do with the alphabets as you see in the example I have 2 words that start with h and in between one that has a p – BLH-Maxx Feb 07 '19 at 10:48
  • Use `Map` instead of Arraylist, then it will be easier to get what you desire. Then sort on keys. – Vishwa Ratna Feb 07 '19 at 10:52

4 Answers4

0

Use comporator to solve your problem like this

Add this code inside you class

  private static Comparator<String> ORDER_MYLIST = new Comparator<String>() {
            public int compare(String d, String d1) {
                int first = Integer.parseInt(d.split(" ")[0]);//since you have space 
                int second = Integer.parseInt(d1.split(" ")[0]);
                return second - first;//change the order if you want
            }
};

Add this code in your calling function

Collections.sort(words, ORDER_MYLIST);

Output:

[2514 human, 105 cat, 98 food, 9 hello, 3 pencil]

Will be as you expect.

This link will give you better understanding on how comporator works https://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html

KishanCS
  • 1,357
  • 1
  • 19
  • 38
0

I think you should create a class to represent the elements in the list. For instance:

public class WordCount {
    public static final Comparator<WordCount> BY_COUNT;

    private static final Pattern PATTERN
            = Pattern.compile("\\s*([0-9]+)\\s+(.*)");

    public final int count;
    public final String word;

    public static WordCount parse(String s) {
        Matcher matcher = PATTERN.matcher(s);
        if (!matcher.matches()) {
            throw new IllegalArgumentException("Syntax error: " + s);
        }
        return new WordCount(
                Integer.parseInt(matcher.group(1)), matcher.group(2));
    }

    public WordCount(int count, String word) {
        this.count = count;
        this.word = word;
    }

    @Override
    public String toString() {
        return count + " " + word;
    }

    static {
        BY_COUNT = (WordCount o1, WordCount o2) -> {
            int r = Integer.compare(o1.count, o2.count);
            if (r == 0) {
                r = o1.word.compareTo(o2.word);
            }
            return r;
        };
    }
}

Your code would then become:

    List<WordCount> words = new ArrayList<>();  
    words.add(WordCount.parse("9 hello"));
    words.add(WordCount.parse("98 food"));
    words.add(WordCount.parse("105 cat"));
    words.add(WordCount.parse("2514 human"));
    words.add(WordCount.parse("3 pencil"));
    words.sort(WordCount.BY_COUNT.reversed());
    words.forEach((wc) -> {
        System.out.println(wc);
    });

With the following result:

2514 human
105 cat
98 food
9 hello
3 pencil
Maurice Perry
  • 9,261
  • 2
  • 12
  • 24
0

You need to have a custom comparator to satisfy your requirement. Java 8 solution:

List<String> words = new ArrayList<>();  
words.add("9 hello");
words.add("98 food");
words.add("105 cat");
words.add("2514 human");
words.add("3 pencil");

// Sort the existing list
words.sort(Comparator.comparing(s -> Integer.parseInt(s.split(" ")[0]), Comparator.reverseOrder()));

// To create new sorted list
List<String> sortedWords = words.stream()
            .sorted(Comparator.comparing(s -> Integer.parseInt(s.split(" ")[0]), Comparator.reverseOrder()))
            .collect(Collectors.toList());
chaitanya89
  • 827
  • 3
  • 20
  • 26
-1

What you've got is exactly lexicographical order because not numbers are compared but their digits alphabetically. If you want other behavior then you should consider implementing your own Comparator in which you'll parse the numbers.

  • As a note, the term is **lexicographical**. Also, the answer looks more like a comment than a full answer. A full answer would probably provide a ready solution, see [answer]. – Zabuzard Feb 07 '19 at 10:36
  • Okay, thanks for your advice – PROgrammer_JARvis Feb 07 '19 at 10:40
  • You do realize that your answer makes no sense when there is a "p" in between 2 "h". Now that said it's more like the sorting is just taking the first digit and grouping all thebstarts with 1 then all that starts with 2 and so on – BLH-Maxx Feb 07 '19 at 10:53