<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <p>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?</p>
    <p>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).</p>
    <p>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.<br>
    </p>
    <p>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?<br>
    </p>
    <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>
    --John<br>
    <br>
    <div class="moz-cite-prefix">On 29/01/2026 11:09, Daniel Peintner
      wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CAAoP7T4WeBEx0_JG74k_31tTNR32+_xfaym-OVXvXbjprrC5wg@mail.gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <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 gmail_quote_container">
        <div dir="ltr" class="gmail_attr">On Wed, Jan 28, 2026 at
          4:51 AM Cormac Redmond <<a
            href="mailto:credmond@certak.com" moz-do-not-send="true"
            class="moz-txt-link-freetext">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 class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">Hi,</div>
              <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
              </div>
              <div class="gmail_default"
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 class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
              </div>
              <div class="gmail_default"
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 class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
              </div>
              <div class="gmail_default"
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 class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
              </div>
              <div class="gmail_default"
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 class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)"><br>
              </div>
              <div class="gmail_default"
                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 class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">...etc.</div>
              <br>
            </div>
            <div><br>
            </div>
            <div>
              <div class="gmail_default"
style="font-family:verdana,sans-serif;font-size:small;color:rgb(0,0,0)">Code:</div>
              <div class="gmail_default"
                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" moz-do-not-send="true">person.id</a>
                  && age == person.age &&
                  Objects.equals(name, <a href="http://person.name"
                    target="_blank" moz-do-not-send="true">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 class="gmail_default"
                style="font-size:small;color:rgb(0,0,0)"><font
                  face="monospace"><br>
                </font></div>
              <div class="gmail_default"
                style="font-size:small;color:rgb(0,0,0)"><font
                  face="monospace"><br>
                </font></div>
              <div class="gmail_default"
                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 class="gmail_default"
                style="font-size:small;color:rgb(0,0,0)"><font
                  face="monospace"><br>
                </font></div>
              <div class="gmail_default"
                style="font-size:small;color:rgb(0,0,0)"><img
                  src="cid:part1.dgRCyqR6.CAcel8rT@gmail.com"
                  alt="sl.gif" class="" width="562" height="422"><br>
              </div>
              <br>
            </div>
            <div>
              <div class="gmail_default"
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>
  </body>
</html>