在java binarySearch中使用多个比较器

时间:2011-03-02 15:26:13

标签: java

如何在java中的binarySearch中使用多个比较器... 我正在尝试对按名称和起始编号排序的参赛者名单进行排序。

问题是,如果两个参赛者具有相同的名称,我会得到一个IndexOutOfBoundsException,所以我想使用起始编号(这是唯一的)进行二次二进制搜索,但仍然使用名称保持正确的顺序。

这就是我现在所拥有的:

static void add(Contestant c){
    int pos = Collections.binarySearch(byName, c, new ConNameCmp());
    if (pos >= 0){
        pos = Collections.binarySearch(byName, c, new ConStartCmp());
    }
    byName.add(-pos-1, c);

2 个答案:

答案 0 :(得分:5)

仅限一位比较者

不要使用两个比较器,使用比较两个值的单个比较器:

public int compare(Foo a, Foo b){
    // compare bar() values first
    int result = a.bar().compareTo(b.bar());
    // compare baz() values only if bar() values are different
    if(result==0){
        result = a.baz().compareTo(b.baz());
    }
    return result;
}

(在你的情况下,bar()是名称,baz()是数字)。

使用库

如果您使用GuavaCommons / Lang

,以这种方式创建比较器要容易得多

番石榴版本:

@Override
public int compare(final Foo a, final Foo b){
    return ComparisonChain
        .start()
        .compare(a.bar(), b.bar())
        .compare(a.baz(), b.baz())
        .result();
}

Commons / Lang版本:

@Override
public int compare(final Foo a, final Foo b){
    return new CompareToBuilder()
        .append(a.bar(), b.bar())
        .append(a.baz(), b.baz())
        .toComparison();
}

(如果任何值为null,这两个版本都不会失败,我上面的快速和脏代码将会出现)

解决问题

我认为你不应该首先进行二元搜索,这看起来很复杂。

为什么不使用TreeSet with a custom comparator?还是Collections.sort(list, comparator)? (对于这两个选项,您可以使用我之前展示的比较器。)

另外,你应该考虑让你的参赛者实施Comparable<Contestant>。这样您就不需要使用外部Comparator。您可以在compareTo()方法中使用与上述相同的逻辑,只需使用this替换其中一个对象。

答案 1 :(得分:0)

您可能已经尝试过此操作,但可能无法使用此解决方案,但如果您可以更改“Contestant”类,则可以扩展“java.lang.Comparable”界面,覆盖Comparable#compareTo(Contestant)方法,以便将名称和起始编号都考虑在内。之后,您将能够根据需要使用Collections.binarySearch(Collection<Contestant>, Contestant)方法。