'Why is my collections.sort leading to different outputs in 2 arraylists with the same data [closed]

I am having some trouble sorting 2 arraylists of mine which have the exact same data, one is received through my API and the other is parsed through ingame text fields, for some reason they are sorted differently even though they are the exact same.

    public ArrayList<String> names = new ArrayList<>();
    AbowAPI api = new AbowAPI();

    @Override
    public void onStart() throws InterruptedException {
        try {
            names = api.getTargets();
            Collections.sort(names);
        } catch (IOException e) {
            log(e.getStackTrace());
        }
    }

    @Override
    public int onLoop() throws InterruptedException {
        if(tabs.getOpen() != Tab.FRIENDS) {
            tabs.open(Tab.FRIENDS);
        } else {
            ArrayList<String> friendList = getFriendNames();
            Collections.sort(friendList);
            log(friendList);
}

This here is the resulting output

[INFO][Bot #1][05/06 07:59:51 em]: [abc, abow42069, adam, bad, bl ack, blood, blue, bye, dead, dog, google, her, him, john wick, light, lol, mad, red]
[INFO][Bot #1][05/06 07:59:51 em]: [abc, abow42069, adam, bad, blood, blue, bl ack, bye, dog, google, her, him, john wick, light, lol, mad, red]

As I try comparing the 2 arraylists they are not also not equal, I need them to be sorted the same way so they match but I'm having troubles with it, any help to why they are sorting in different ways?

This is my API call to get the targets, maybe this is what is causing the weird bug?

enter code here
    URL url = new URL("http://127.0.0.1:5000/snipes");
    HttpURLConnection con = (HttpURLConnection) url.openConnection();
    con.setRequestMethod("GET");

    BufferedReader in = new BufferedReader(
            new InputStreamReader(con.getInputStream()));
    String inputLine;
    ArrayList<String> content = new ArrayList<>();
    while ((inputLine = in.readLine()) != null) {
        content.add(inputLine);
    }
    in.close();

    return content;


Solution 1:[1]

The third character in "bl ack" is in one case a character that sorts before the lower-case alphabetics, and in the other case a character that sorts after them.

I would go with the hunch that says the first one is the "normal" space, and the second one is some other space (of which there are a few), and therefore the second one will have a character code greater than 127 - i.e., outside the usual ASCII range - which is possible since Java does not use ASCII.

To debug, I'd insert code like this:

for (String f : friendList)
    for (int k=0; k<f.length(); k++) {
        char c = f.charAt(k);
        if (c > 127) 
            System.out.printf("String '%s' char %d has code %d (%x)%n",
                              f, k, c, c);
    }

It's not pretty but it'll get the job done. It'll work equally well if I'm wrong that the 'funny' character is a form of space, but is just something the logger is replacing by space. Armed with the character code in hex, you can look it up at unicode.org.

Replace 'printf' with anything more suitable to your development environment, if appropriate.

(For the purists, I'm guessing it's not going to be a surrogate pair, thus I'm using char rather than codepoint).

Once you know what you're dealing with, you can devise a handling strategy, which might be "replace the funny character with plain old space".

Edited since we now know the character is non-breaking space, 00a0 in hex.

You could, for example, change this:

ArrayList<String> friendList = getFriendNames();
Collections.sort(friendList);

to this:

ArrayList<String> friendList = new ArrayList<>();
ArrayList<String> temp = getFriendNames();
for (String t : temp) {
    friendList.add(t.replaceAll("\\h", " "));
}
Collections.sort(friendList);

The \h represents any horizontal whitespace in a Java regular expression Pattern, which includes the non-breaking space and others. So we're going above and beyond the observed problem, normalizing all possible "spaces".

It would probably be better to make the same replacement in the getFriendNames method, but I don't think you've shown that code. Nevertheless, I hope you get the idea.

(Code typed in, not tested).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1