Java 按属性对列表排序,但保持相同属性的顺序

Java 按属性对列表排序,但保持相同属性的顺序,java,algorithm,sorting,Java,Algorithm,Sorting,我有一个列表,可以如下所示: {A[1],A[2],B[1],A[3],B[2],B[3],A[4]} 而A,B是列表中对象的属性。 这些数字表示具有相同属性的对象相互关联的顺序 现在,我想对列表进行排序,以便得到以下结果: {A[1],A[2],A[3],A[4],B[1],B[2],B[3]} 具体来说,这意味着与具有相同属性的其他对象相关的对象的顺序应保持不变,但一般顺序应由属性决定。问题在于,相互关联的顺序不能由附加属性确定,它只是由根列表中的顺序指定 我该怎么做呢?只需定义一个新的

我有一个列表,可以如下所示:

{A[1],A[2],B[1],A[3],B[2],B[3],A[4]}

A,B
是列表中对象的属性。
这些数字表示具有相同属性的对象相互关联的顺序


现在,我想对列表进行排序,以便得到以下结果:

{A[1],A[2],A[3],A[4],B[1],B[2],B[3]}


具体来说,这意味着与具有相同属性的其他对象相关的对象的顺序应保持不变,但一般顺序应由属性决定。问题在于,相互关联的顺序不能由附加属性确定,它只是由根列表中的顺序指定


我该怎么做呢?

只需定义一个新的比较器,在其中指定您的需求:检查对象是否具有相同的属性,在这种情况下,根据根列表中的位置指定优先级;否则,按属性本身排序

Collections.sort(rootlist, new YourComparator());

class YourComparator implements Comparator<YourClass> {
    @Override
    public int compare(YourClass a, YourClass b) {
        if(a.attribute == b.attribute){
            return rootlist.indexOf(a) < rootlist.indexOf(b) ? -1 : rootlist.indexOf(a) == rootlist.indexOf(b) ? 0 : 1;
        }
        else 
            return a.attribute < b.attribute ? -1 : 1;

    }
}
Collections.sort(rootlist,newyourcomparator());
类YourComparator实现Comparator{
@凌驾
公共整数比较(你的类a,你的类b){
如果(a.attribute==b.attribute){
返回rootlist.indexOf(a)
我不确定已经实现的方法
list.sort()
是否保持了您的条件,因此我建议您使用O(n²)计算进行简单排序,假设您的
compare
-方法返回0,如果属性相同:

List<T> sortList(List<T> list){
    for(int ind=1; ind<list.size(); ind++){
        for(int indBack=ind; indBack>0; indBack--){
            if(compare(list.get(indBack), list.get(indBack-1))==1){
                T tempSave = list.get(indBack-1);
                list.set(indBack-1, list.get(indBack));
                list.set(indBack, tempSave);
            }
        }
    }
    return list;
}
列表排序列表(列表){
对于(int ind=1;ind0;indBack--){
if(比较(list.get(indBack),list.get(indBack-1))==1){
T tempSave=list.get(indBack-1);
list.set(indBack-1,list.get(indBack));
list.set(indBack、tempSave);
}
}
}
退货清单;
}

只需使用
List.sort
方法,即可根据属性值对所有元素进行排序

具有相同属性值的元素将保持插入顺序不变

例如:

@Test
public void testSortList() {

    List<Element> list = new ArrayList<>();
    list.add(new Element("A", 1));
    list.add(new Element("A", 2));
    list.add(new Element("B", 1));
    list.add(new Element("A", 3));
    list.add(new Element("B", 2));

    list.sort((element1, element2) -> element1.getValue().compareTo(element2.getValue()));

    assertThat(list.get(0).getValue()).isEqualTo("A");
    assertThat(list.get(0).getPosition()).isEqualTo(1);
    assertThat(list.get(1).getValue()).isEqualTo("A");
    assertThat(list.get(1).getPosition()).isEqualTo(2);
    assertThat(list.get(2).getValue()).isEqualTo("A");
    assertThat(list.get(2).getPosition()).isEqualTo(3);
    assertThat(list.get(3).getValue()).isEqualTo("B");
    assertThat(list.get(3).getPosition()).isEqualTo(1);
    assertThat(list.get(4).getValue()).isEqualTo("B");
    assertThat(list.get(4).getPosition()).isEqualTo(2);
}
你可以用


不知道Java内置方法是否使用了一些稳定的排序(比如TimSort)。如果没有,您很容易找到插入排序或合并排序实现。

集合的排序方法是复制列表进行排序(然后应用值),还是直接对列表进行排序。因为在第二种情况下,它可能会更改具有相同属性的元素的顺序,而无需直接比较它们(取决于算法,例如,它会在一个点上比较第一个和最后一个元素)。在第二种情况下,您的解决方案可能不起作用!在文档中:“此实现将指定的列表转储到数组中,对数组进行排序,并在列表上迭代,从数组中的相应位置重置每个元素”。所以情况不应该如此。在任何情况下,您都可以将根列表的副本传递给Collections.sort(如果这是一个问题)。好的,那么它应该可以完成这项工作。如果您传递一个副本,这不会改变问题,因为比较器会查看(可能已更改)复制的列表。但既然文档声明它是一个临时副本,这应该是最好的解决方案。我的意思是将副本(通过值,而不是对同一列表的另一个引用)传递给排序方法,但仍然使用Comparator.compare()中的原始列表。但是在任何情况下都没有必要。谢谢,我不知道插入顺序是使用列表排序隐式的!小心。这取决于列表的实现。ArrayList是一个有序列表
class Element {

  /** Attribute used to sort the elements */
  private String value;

  /** Attribute used to remember the original position of this element in the list */
  private int position;

  public Element(String value, int position) {
    this.value = value;
    this.position = position;
  }

  public String getValue() {
    return value;
  }

  public int getPosition() {
    return position;
  }

  /** Insert equals and hashCode! */
}