Isn't this a different case? If I understood correctly, you expect a new entry to be added below an existing entry that happens to be equal?
Basically, you expect the Table to act as a list sorted by index (you're inserting at a the current selected index + 1 in unsorted space) for copy/paste operations, while at the same time expecting the table to be sorted on some key that is not its index (and doesn't include the index in the comparator). So while the copy/paste indeed occurs below the existing entry (in index sorted view), the sorted view is completely unaware of this, and only sees a new entry. The SortedList could of course insert this new item after any existing items, but what if the user selected "insert before" or some such option? Or what if the list was sorted in reverse? Does that change where the paste ends up (above or below still)? What if there are 5 rows with the same value, should it insert it after some "selected row" that it doesn't know about? The solution IMHO is to make this simply crystal clear in your Comparator. If equal items should be ordered in insertion order, then the index should be part of the comparator. Any decision that SortedList makes could be correct for some use cases, and incorrect for others. --John On 29/01/2026 11:09, Daniel Peintner wrote: > Hi, > > I had and still have the same problem in a similar situation. > > The situation is as follows. A table contains a list of entries. A > user selects an entry and performs a copy and paste operation (in > order to modify the entry later). > In this situation, the copied entry is identical by nature (Comparator > returns 0). > > Even if I insert the *new* entry into the underlying list after the > existing entry, SortedList decides to display the entry *before* the > existing entry. > > This is confusing for a user. > > If there is a good solution for this, it would be helpful. > However, I agree with Cormac Redmond that, ideally, the order should > not change if the Comparator returns 0 (zero). > > Thanks, > > -- Daniel > > > > On Wed, Jan 28, 2026 at 4:51 AM Cormac Redmond <[email protected]> > wrote: > > Hi, > > I have noticed a troublesome quirk with SortedList which causes > unexpected re-positioning of elements in its list. > > This is a noticeable problem when you are, for example, sorting a > TableView on a column and re-insert an identical element at the > same index in the source list (i.e., nothings changing). E.g., if > your goal is to refresh a single row, even when there's no > difference in the underlying object, SortedList can still shift > its place in its arrays and hence the row shifts visibly in the > table. On large tables, this can be a huge jump, outside of view. > This occurs when the sort column value shares the same value with > other rows (i.e., in my code sample below, multiple people are > aged 62 and sorting is by age). > > Sample below code and output below. The bit in green represents > what I would expect on each subsequent printout, but the bit in > red shows the random re-arrangement of elements. > > There's no need to include a full TableView example to show this. > But I've included a small gif too, for example. > > ---- Source Initial ---- > Person item [0]: Person[name=Bob, age=60, id=0] > Person item [1]: Person[name=Alice, age=70, id=1] > Person item [2]: Person[name=Diana, age=30, id=2] > Person item [3]: Person[name=Frank1, age=62, id=3] > Person item [4]: Person[name=Eve, age=62, id=4] > Person item [5]: Person[name=Frank2, age=62, id=5] > Person item [6]: Person[name=Jim, age=62, id=6] > Person item [7]: Person[name=Ivy, age=62, id=7] > Person item [8]: Person[name=Jack, age=53, id=8] > > ---- Sorted Initial (Subsequent Prints Should Match This, But > Don't) ---- > Person item [0]: Person[name=Diana, age=30, id=2] > Person item [1]: Person[name=Jack, age=53, id=8] > Person item [2]: Person[name=Bob, age=60, id=0] > Person item [3]: Person[name=Frank1, age=62, id=3] > Person item [4]: Person[name=Eve, age=62, id=4] > Person item [5]: Person[name=Frank2, age=62, id=5] > Person item [6]: Person[name=Jim, age=62, id=6] > Person item [7]: Person[name=Ivy, age=62, id=7] > Person item [8]: Person[name=Alice, age=70, id=1] > > ---- Sorted After Identical Replace Index 5 ---- > Person item [0]: Person[name=Diana, age=30, id=2] > Person item [1]: Person[name=Jack, age=53, id=8] > Person item [2]: Person[name=Bob, age=60, id=0] > Person item [3]: Person[name=Frank2, age=62, id=5] > Person item [4]: Person[name=Frank1, age=62, id=3] > Person item [5]: Person[name=Eve, age=62, id=4] > Person item [6]: Person[name=Jim, age=62, id=6] > Person item [7]: Person[name=Ivy, age=62, id=7] > Person item [8]: Person[name=Alice, age=70, id=1] > > ---- Sorted After Identical Replace Index 4 ---- > Person item [0]: Person[name=Diana, age=30, id=2] > Person item [1]: Person[name=Jack, age=53, id=8] > Person item [2]: Person[name=Bob, age=60, id=0] > Person item [3]: Person[name=Eve, age=62, id=4] > Person item [4]: Person[name=Frank2, age=62, id=5] > Person item [5]: Person[name=Frank1, age=62, id=3] > Person item [6]: Person[name=Jim, age=62, id=6] > Person item [7]: Person[name=Ivy, age=62, id=7] > Person item [8]: Person[name=Alice, age=70, id=1] > > ---- Sorted After Identical Replace Index 3 ---- > Person item [0]: Person[name=Diana, age=30, id=2] > Person item [1]: Person[name=Jack, age=53, id=8] > Person item [2]: Person[name=Bob, age=60, id=0] > Person item [3]: Person[name=Frank1, age=62, id=3] > Person item [4]: Person[name=Eve, age=62, id=4] > Person item [5]: Person[name=Frank2, age=62, id=5] > Person item [6]: Person[name=Jim, age=62, id=6] > Person item [7]: Person[name=Ivy, age=62, id=7] > Person item [8]: Person[name=Alice, age=70, id=1] > > ...etc. > > > Code: > public class SortedListBehaviour { > > public static void main(String[] args) { > > ObservableList<Person> personList = > FXCollections.observableArrayList(); > > personList.addAll( > new Person("Bob", 60, 0), > new Person("Alice", 70, 1), > new Person("Diana", 30, 2), > new Person("Frank1", 62, 3), > new Person("Eve", 62, 4), > new Person("Frank2", 62, 5), > new Person("Jim", 62, 6), > new Person("Ivy", 62, 7), > new Person("Jack", 53, 8) > ); > > SortedList<Person> sortedList = new > SortedList<>(personList, Comparator.comparing(Person::age)); > > // Starting out > printList(personList, "Source Initial"); > > // This is sorted by age, all subsequent prints should > look like this, but they don't > printList(sortedList, "Sorted Initial (Subsequent Prints > Should Match This, But Don't)"); > > personList.set(5, new Person("Frank2", 62, 5)); // Replace > with identical, at same index > printList(sortedList, "Sorted After Identical Replace > Index 5"); > > personList.set(4, new Person("Eve", 62, 4)); // Replace > with identical, at same index > printList(sortedList, "Sorted After Identical Replace > Index 4"); > > personList.set(3, new Person("Frank1", 62, 3)); // > Replace with identical, at same index > printList(sortedList, "Sorted After Identical Replace > Index 3"); > } > > private static void printList(final List<Person> list, final > String source) { > System.out.println("\n---- " + source + " ----"); > for (int i = 0; i < list.size(); i++) { > final Person next = list.get(i); > System.out.println("Person item [" + i + "]: " + next); > } > } > > public record Person(String name, int age, int id) { > @Override > public boolean equals(final Object o) { > if (o == null || getClass() != o.getClass()) { > return false; > } > final Person person = (Person) o; > return id == person.id <http://person.id> && age == > person.age && Objects.equals(name, person.name <http://person.name>); > } > > @Override > public int hashCode() { > return Objects.hash(name, age, id); > } > } > } > > > UI example also; the "Refresh" item here replaces the object with > an identical object and the same index, yet it will often jump > around the table as you can see, and selection can change too. > > sl.gif > > I understand that strictly speaking the list is still sorted > correctly (by age), but SortedList could make some effort to > reduce re-arranging already-present elements. > > > > Regards, > * > * > *Cormac Redmond* > > >
