Java 自定义比较器

Java 自定义比较器,java,list,sorting,comparator,Java,List,Sorting,Comparator,给出以下列表:“A”、“B”、“C”、“D”、“E”、“F”、“G” 我需要一个比较器来进行以下排序: 指定某个元素(例如“D”) 从元素开始 然后是原始列表中的所有以下元素,按原始顺序排列 然后是原始列表中所有前面的元素,按原始顺序排列 结果将是:“D”、“E”、“F”、“G”、“A”、“B”、“C” 请注意,我知道我可以做以下类似的事情: List<String> following = myList.subList(myList.indexOf("D") + 1, myL

给出以下列表:
“A”、“B”、“C”、“D”、“E”、“F”、“G”


我需要一个比较器来进行以下排序:

  • 指定某个元素(例如
    “D”
  • 从元素开始
  • 然后是原始列表中的所有以下元素,按原始顺序排列
  • 然后是原始列表中所有前面的元素,按原始顺序排列
结果将是:
“D”、“E”、“F”、“G”、“A”、“B”、“C”


请注意,我知道我可以做以下类似的事情:

List<String> following = myList.subList(myList.indexOf("D") + 1, myList.size());
List<String> preceding = myList.subList(0, myList.indexOf("D"));
List<String> newList = Stream.of(Collections.singletonList("D"), following, preceding)
                       .flatMap(List::stream)
                       .collect(Collectors.toList());

如果我问对了问题,你应该做什么
Collections.sort(myList,myComparator)

然后我可以建议您使用一个已定义的collator:

List<String> myList = Arrays.asList("A", "B", "C", "D", "E", "F", "G");
System.out.println(myList);
String rules = "< d,D < e,E < f,F < g,G < a,A < b,B < c,C";

RuleBasedCollator ruleBasedCollator = new RuleBasedCollator(rules);
Collections.sort(myList, ruleBasedCollator);
System.out.println(myList);
List myList=Arrays.asList(“A”、“B”、“C”、“D”、“E”、“F”、“G”);
System.out.println(myList);
字符串规则=“
这里的规则是
,这意味着哪些字符比其他字符的权重更高。。。其余的是通常的排序方法

输出

[A、B、C、D、E、F、G]

[D,E,F,G,A,B,C]


在这里使用
比较器没有多大意义,因为它效率很低(因为必须在原始列表中找到两个被比较元素的索引,这将导致每次比较都需要线性时间)

如果列表中包含重复项,它可能会失败

但是,既然你问了,像这样的事情可能会奏效:

public int compare(T o1, T o2) {
    if (o1.equals(o2)
        return true;
    int i1 = list.indexOf(o1);
    int i2 = list.indexOf(o2);
    int ie = list.indexOf(element); // this can be done in the constructor of the Comparator
    // now you have to check whether i1 and i2 are smaller than or larger than
    // ie, and based on that determine which of the corresponding elements should come
    // first
}
或者,直接打电话

Collections.rotate(list,list.size() - list.indexOf(element));

我想这就是你想要的:

class ImposedOrder<T> implements Comparator<T> {

    private final List<T> list;
    private final int startIndex;

    ImposedOrder(List<T> list, T startElement) {
        this.list = new ArrayList<>(list);
        this.startIndex = list.indexOf(startElement);
        if (startIndex < 0) {
            throw new IllegalArgumentException();
        }
    }

    @Override
    public int compare(T t1, T t2) {
        int t1Index = list.indexOf(t1);
        int t2Index = list.indexOf(t2);
        return Integer.compare(adjust(t1Index), adjust(t2Index));
    }

    private int adjust(int rawIndex) {
        if (rawIndex >= startIndex) {
            return rawIndex;
        }
        return rawIndex + list.size();
    }
}

我知道这是可能的,但它是混乱的和不安全

将第一个块推到末尾的想法是添加一个
字符串
,以迫使这些值变大。这样,如果与比较时看起来像“ZA”,那么“A”比“G”大

    List<String> list = Arrays.asList(new String[]{ "A", "B", "C", "D", "E", "F"});
    final String split = "D";
    Collections.sort(list, new Comparator<String>(){
        public int compare(String o1, String o2) {
            //Prepend with a big String value (like "ZZZZ") if it is before the value `split`.
            if(o1.compareTo(split) < 0)
                o1 = "ZZZZ" + o1;
            if(o2.compareTo(split) < 0)
                o2 = "ZZZZ" + o2;

            return o1.compareTo(o2); //then compare
        }
    });

    System.out.println(list);
List List=Arrays.asList(新字符串[]{“A”、“B”、“C”、“D”、“E”、“F”});
最终字符串拆分=“D”;
Collections.sort(list,newcomparator(){
公共整数比较(字符串o1、字符串o2){
//如果在值“split”之前,则在前面加一个大字符串值(如“ZZZZ”)。
如果(o1.与(拆分)相比<0)
o1=“ZZZZ”+o1;
如果(o2.与(拆分)相比<0)
o2=“ZZZZ”+o2;
返回o1.compareTo(o2);//然后比较
}
});
系统输出打印项次(列表);
[D,E,F,A,B,C]


这是不安全的,因为用一个更大的安全值作为前缀可能会很复杂,我考虑过使用
Character.MAX\u value
,但我不确定这样会更安全。好的,使用
拆分
值本身可能更简单。

您需要比较元素的索引

private static class MyComparator<T> implements Comparator<T> {

    private final List<T> list;
    private final int elementIndex;

    private MyComparator(List<T> list, T element) {
        // keep original order
        this.list = new ArrayList<>(list);
        this.elementIndex = list.indexOf(element);
    }

    @Override
    public int compare(T o1, T o2) {
        int i1 = list.indexOf(o1);
        int i2 = list.indexOf(o2);
        if (i1 == elementIndex) {
            // "shift" first element left
            return -1;
        } else if (i2 == elementIndex) {
            // "shift" secont element left
            return 1;
        }
        boolean left1 = i1 < elementIndex;
        boolean left2 = i2 < elementIndex;
        if (left1 != left2) {
            // different part
            return i2 - elementIndex;
        } else {
            // same part
            return i1 - i2;
        }
    }
}
私有静态类MyComparator实现Comparator{
私人最终名单;
私有最终内部元素索引;
专用MyComparator(列表,T元素){
//维持原有秩序
this.list=新的ArrayList(列表);
this.elementIndex=list.indexOf(元素);
}
@凌驾
公共整数比较(tO1,tO2){
inti1=list.indexOf(o1);
int i2=列表索引Of(o2);
if(i1==elementIndex){
//“shift”第一个元素向左移动
返回-1;
}else if(i2==elementIndex){
//“shift”secont元素左移
返回1;
}
布尔left1=i1
这个想法是基于列表中的原始索引比较元素的权重-如果当前元素的索引>=指定特定元素的索引(例如“D”),则新列表中的索引应移到左侧,“D”的索引正好是所需的偏移量

int weightO1 = list.indexOf(o1) - list.indexOf(element);
在相反的情况下(list.indexOf(o1)
int weightO1 = list.indexOf(o1) + list.size();
我将采用局部法计算重量:

   int weight (T o) {
    return int weight = list.indexOf(o) < list.indexOf(element) ? list.indexOf(o) + list.size() : list.indexOf(o) - list.indexOf(element);
   }

如果存在相同的整数,则整数应为
0
;如果
o1
o2
之前,则整数应为
;对于相反的整数,则整数应为
(待确认,可能是相反的整数)。但是由于
T
没有扩展任何内容,您只有
Object
提供的内容,因此没有太多可比较的内容。这是在我清楚比较器是如何工作的,我只是不清楚如何为给定的排序算法生成这些数字:)你确定你的设计是正确的吗?在我看来,您需要一个基于树的数据结构。“我需要一个比较器,它可以进行以下排序”=>这句话是您困惑的第一点。比较器只比较两个元素。它不进行任何排序,尽管它有助于排序算法获得“正确”的排序顺序。事实上,这个问题对我来说有点不清楚。也许你可以告诉我们你将如何使用这样一个比较器?好吧,因为比较器是通过比较每个元素和下一个元素来对列表进行“冒泡排序”的,这并不容易。。。我想如果你给比较器一个“元素”,它会改变逻辑,这是可能的,但我不认为它值得,我认为这不是什么asked@nilesh你是对的,现在答案是正确的!输出不正确:
“D”、“E”、“F”、“G”、“A”、“B”、“C”
,在“D”之后的所有内容都应跟随它。但是我不知道
收银机
,谢谢!不完全是我所期望的,但是
RuleBasedCollator
很有趣,我不知道这个!非常感谢。我想你会的
int weightO1 = list.indexOf(o1) + list.size();
   int weight (T o) {
    return int weight = list.indexOf(o) < list.indexOf(element) ? list.indexOf(o) + list.size() : list.indexOf(o) - list.indexOf(element);
   }
@Override
  public int compare(T o1, T o2) {
     return weight(o1) - weight(o2); 
  }