<div dir="ltr"><div dir="ltr"><div>Hi John,</div><div><br></div><div>Thank you very much for your feedback.</div></div><div class="gmail_quote gmail_quote_container"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><p>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.<br></p></div></blockquote><div><br></div>You might be right that one could (should?) of course take into account the original order of the underlying list in the comparator to be sure.<br><br>On the other hand, the sort method of Collections [1] states<br><br>>  This sort is guaranteed to be stable: equal elements will not be reordered as a result of the sort.</div><div class="gmail_quote gmail_quote_container"><br></div><div class="gmail_quote gmail_quote_container">I am not saying it is a *real* conflict, but my assumption/expectation was that the order of a SortedList behaves somewhat the same.</div><div class="gmail_quote gmail_quote_container"><div><br></div><div>Thanks,</div><div><br></div><div>-- Daniel</div><div><br></div><div>[1] <a href="https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Collections.html#sort(java.util.List)">https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/Collections.html#sort(java.util.List)</a></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div><p>
    </p>
    --John<br>
    <br>
    <div>On 29/01/2026 11:09, Daniel Peintner
      wrote:<br>
    </div>
    <blockquote type="cite">
      
      <div dir="ltr">Hi,<br>
        <br>
        I had and still have the same problem in a similar situation. <br>
        <br>
        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).<br>
        <div>In this situation, the copied entry is identical by nature
          (Comparator returns 0).</div>
        <div><br>
        </div>
        <div>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.</div>
        <br>
        This is confusing for a user.<br>
        <br>
        <div>If there is a good solution for this, it would be helpful.</div>
        <div>However, I agree with Cormac Redmond that, ideally, the
          order should not change if the Comparator returns 0 (zero).</div>
        <br>
        Thanks,<br>
        <br>
        <div>-- Daniel</div>
        <div><br>
        </div>
        <div><br>
        </div>
      </div>
      <br>
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">On Wed, Jan 28, 2026 at
          4:51 AM Cormac Redmond <<a href="mailto:credmond@certak.com" target="_blank">credmond@certak.com</a>>
          wrote:<br>
        </div>
        <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
          <div dir="ltr">
            <div>
              <div style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">Hi,</div>
              <div style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
              </div>
              <div style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">I
                have noticed a troublesome quirk with SortedList which
                causes unexpected re-positioning of elements in its
                list.</div>
              <div style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
              </div>
              <div style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">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).</div>
              <div style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
              </div>
              <div style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">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.</div>
              <div style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
              </div>
              <div style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">There's
                no need to include a full TableView example to show
                this. But I've included a small gif too, for example.</div>
              <div style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
              </div>
              <div style="font-size:small;color:rgb(0,0,0)"><font face="monospace"><span style="color:rgb(34,34,34)">----
                    Source Initial ----</span></font></div>
              <font face="monospace">Person item [0]: Person[name=Bob,
                age=60, id=0]<br>
                Person item [1]: Person[name=Alice, age=70, id=1]<br>
                Person item [2]: Person[name=Diana, age=30, id=2]<br>
                Person item [3]: Person[name=Frank1, age=62, id=3]<br>
                Person item [4]: Person[name=Eve, age=62, id=4]<br>
                Person item [5]: Person[name=Frank2, age=62, id=5]<br>
                Person item [6]: Person[name=Jim, age=62, id=6]<br>
                Person item [7]: Person[name=Ivy, age=62, id=7]<br>
                Person item [8]: Person[name=Jack, age=53, id=8]<br>
                <br>
                ---- Sorted Initial (Subsequent Prints Should Match
                This, But Don't) ----<br>
                Person item [0]: Person[name=Diana, age=30, id=2]<br>
                Person item [1]: Person[name=Jack, age=53, id=8]<br>
                Person item [2]: Person[name=Bob, age=60, id=0]<br>
                <span style="background-color:rgb(0,255,0)"><span class="gmail_default" style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"></span>Person
                  item [3]: Person[name=Frank1, age=62, id=3]<br>
                  Person item [4]: Person[name=Eve, age=62, id=4]<br>
                  Person item [5]: Person[name=Frank2, age=62, id=5]</span><br>
                Person item [6]: Person[name=Jim, age=62, id=6]<br>
                Person item [7]: Person[name=Ivy, age=62, id=7]<br>
                Person item [8]: Person[name=Alice, age=70, id=1]<br>
                <br>
                ---- Sorted After Identical Replace Index 5 ----<br>
                Person item [0]: Person[name=Diana, age=30, id=2]<br>
                Person item [1]: Person[name=Jack, age=53, id=8]<br>
                Person item [2]: Person[name=Bob, age=60, id=0]<br>
                <span style="background-color:rgb(234,153,153)">Person
                  item [3]: Person[name=Frank2, age=62, id=5]<br>
                  Person item [4]: Person[name=Frank1, age=62, id=3]<br>
                  Person item [5]: Person[name=Eve, age=62, id=4]</span><br>
                Person item [6]: Person[name=Jim, age=62, id=6]<br>
                Person item [7]: Person[name=Ivy, age=62, id=7]<br>
                Person item [8]: Person[name=Alice, age=70, id=1]<br>
                <br>
                ---- Sorted After Identical Replace Index 4 ----<br>
                Person item [0]: Person[name=Diana, age=30, id=2]<br>
                Person item [1]: Person[name=Jack, age=53, id=8]<br>
                Person item [2]: Person[name=Bob, age=60, id=0]<br>
                <span style="background-color:rgb(234,153,153)">Person
                  item [3]: Person[name=Eve, age=62, id=4]<br>
                  Person item [4]: Person[name=Frank2, age=62, id=5]<br>
                  Person item [5]: Person[name=Frank1, age=62, id=3]</span><br>
                Person item [6]: Person[name=Jim, age=62, id=6]<br>
                Person item [7]: Person[name=Ivy, age=62, id=7]<br>
                Person item [8]: Person[name=Alice, age=70, id=1]<br>
                <br>
                ---- Sorted After Identical Replace Index 3 ----<br>
                Person item [0]: Person[name=Diana, age=30, id=2]<br>
                Person item [1]: Person[name=Jack, age=53, id=8]<br>
                Person item [2]: Person[name=Bob, age=60, id=0]<br>
                <span style="background-color:rgb(234,153,153)">Person
                  item [3]: Person[name=Frank1, age=62, id=3]<br>
                  Person item [4]: Person[name=Eve, age=62, id=4]<br>
                  Person item [5]: Person[name=Frank2, age=62, id=5]</span><br>
                Person item [6]: Person[name=Jim, age=62, id=6]<br>
                Person item [7]: Person[name=Ivy, age=62, id=7]<br>
                Person item [8]: Person[name=Alice, age=70, id=1]</font><br>
              <br clear="all">
            </div>
            <div>
              <div style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">...etc.</div>
              <br>
            </div>
            <div><br>
            </div>
            <div>
              <div style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">Code:</div>
              <div style="font-size:small;color:rgb(0,0,0)"><font face="monospace">public class SortedListBehaviour {<br>
                  <br>
                      public static void main(String[] args) {<br>
                  <br>
                          ObservableList<Person> personList =
                  FXCollections.observableArrayList();<br>
                  <br>
                          personList.addAll(<br>
                              new Person("Bob", 60, 0),<br>
                              new Person("Alice", 70, 1),<br>
                              new Person("Diana", 30, 2),<br>
                              new Person("Frank1", 62, 3),<br>
                              new Person("Eve", 62, 4),<br>
                              new Person("Frank2", 62, 5),<br>
                              new Person("Jim", 62, 6),<br>
                              new Person("Ivy", 62, 7),<br>
                              new Person("Jack", 53, 8)<br>
                          );<br>
                  <br>
                          SortedList<Person> sortedList = new
                  SortedList<>(personList,
                  Comparator.comparing(Person::age));<br>
                  <br>
                          // Starting out<br>
                          printList(personList, "Source Initial");<br>
                  <br>
                          // This is sorted by age, all subsequent
                  prints should look like this, but they don't<br>
                          printList(sortedList, "Sorted Initial
                  (Subsequent Prints Should Match This, But Don't)");<br>
                  <br>
                          personList.set(5, new Person("Frank2", 62,
                  5)); // Replace with identical, at same index<br>
                          printList(sortedList, "Sorted After Identical
                  Replace Index 5");<br>
                  <br>
                          personList.set(4, new Person("Eve", 62, 4));
                   // Replace with identical, at same index<br>
                          printList(sortedList, "Sorted After Identical
                  Replace Index 4");<br>
                  <br>
                          personList.set(3, new Person("Frank1", 62,
                  3));  // Replace with identical, at same index<br>
                          printList(sortedList, "Sorted After Identical
                  Replace Index 3");<br>
                      }<br>
                  <br>
                      private static void printList(final
                  List<Person> list, final String source) {<br>
                          System.out.println("\n---- " + source + "
                  ----");<br>
                          for (int i = 0; i < list.size(); i++) {<br>
                              final Person next = list.get(i);<br>
                              System.out.println("Person item [" + i +
                  "]: " + next);<br>
                          }<br>
                      }<br>
                  <br>
                      public record Person(String name, int age, int id)
                  {<br>
                          @Override<br>
                          public boolean equals(final Object o) {<br>
                              if (o == null || getClass() !=
                  o.getClass()) {<br>
                                  return false;<br>
                              }<br>
                              final Person person = (Person) o;<br>
                              return id == <a href="http://person.id" target="_blank">person.id</a>
                  && age == person.age &&
                  Objects.equals(name, <a href="http://person.name" target="_blank">person.name</a>);<br>
                          }<br>
                  <br>
                          @Override<br>
                          public int hashCode() {<br>
                              return Objects.hash(name, age, id);<br>
                          }<br>
                      }<br>
                  }</font><br>
              </div>
              <div style="font-size:small;color:rgb(0,0,0)"><font face="monospace"><br>
                </font></div>
              <div style="font-size:small;color:rgb(0,0,0)"><font face="monospace"><br>
                </font></div>
              <div style="font-size:small;color:rgb(0,0,0)"><font face="verdana, sans-serif">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.</font></div>
              <div style="font-size:small;color:rgb(0,0,0)"><font face="monospace"><br>
                </font></div>
              <div style="font-size:small;color:rgb(0,0,0)"><img src="cid:ii_19c27959ec8ca45b2af1" alt="sl.gif" width="562" height="422"><br>
              </div>
              <br>
            </div>
            <div>
              <div style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">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.</div>
              <br>
            </div>
            <div><br>
            </div>
            <div>
              <div dir="ltr" class="gmail_signature">
                <div dir="ltr">
                  <div><font face="verdana, sans-serif" color="#000000"><br>
                    </font></div>
                  <div><font face="verdana, sans-serif" color="#000000">Regards,</font></div>
                  <div><font face="verdana, sans-serif" color="#000000"><b><br>
                      </b></font></div>
                  <font face="verdana, sans-serif" color="#000000"><b>Cormac
                      Redmond</b></font>
                  <div><br>
                  </div>
                  <div><br>
                  </div>
                  <div><br>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </blockquote>
      </div>
    </blockquote>
  </div>
</blockquote></div></div>