Java:根据大小对树集进行排序

Java:根据大小对树集进行排序,java,sorting,set,Java,Sorting,Set,我正在寻找一种对一组集合进行排序的方法—更具体地说,数据结构需要具有以下属性: “外部”集合和“内部”集合都应该是集合,即包含的集合中不应该有重复的元素,也不应该有重复的集合 集合应该按照所包含集合的长度按升序排序,即{{A}、{A,B}、{A,C,F}、{B,D,F}是有效的,而{A,C,F}、{A,B}、{B,D,F}、{A,B}、{A,D,F}、{A}不是有效的 应该可以迭代单个包含的集合以及所有集合。当然,迭代所有集合时,应该根据它们各自的大小按升序列出它们 如果两个集合的大小相同,则

我正在寻找一种对一组集合进行排序的方法—更具体地说,数据结构需要具有以下属性:

  • “外部”集合和“内部”集合都应该是集合,即包含的集合中不应该有重复的元素,也不应该有重复的集合
  • 集合应该按照所包含集合的长度按升序排序,即{{A}、{A,B}、{A,C,F}、{B,D,F}是有效的,而{A,C,F}、{A,B}、{B,D,F}、{A,B}、{A,D,F}、{A}不是有效的
  • 应该可以迭代单个包含的集合以及所有集合。当然,迭代所有集合时,应该根据它们各自的大小按升序列出它们
  • 如果两个集合的大小相同,则顺序可能是任意的
我的基本方法是
树集
,尽管由于所包含的树集需要按照自定义行为进行排序,我编写了一个包装类(省略了不必要的细节,例如其他构造函数和方法):

import java.util.TreeSet;
导入java.util.Iterator;
导入java.util.Collection;
公共类WrappedSet实现了compariable,Iterable{
受保护树集集;
公共包装集(收集收集){
集合=新树集合(集合);
}
公共整数大小(){
返回set.size();
}
@凌驾
公共迭代器迭代器(){
返回set.iterator();
}
@凌驾
公共int比较(WrappedSet其他){
if(set.equals(other.set)){
返回0;
}
否则{
返回(set.size()>=other.set.size())?1:-1;
}
}
@凌驾
公共字符串toString(){
返回set.toString();
}
}
为了显示问题,我使用以下主要功能:

public static void main( String[] args ) {
    TreeSet< WrappedSet< String >> wsets = new TreeSet< WrappedSet< String >>();

    for ( String arg : args ) {
        wsets.add( new WrappedSet< String >( new TreeSet< String >( Arrays.asList( arg.split( "," )))));
    }

    System.out.println( "Input sets: " + Arrays.toString( wsets.toArray()));
}
publicstaticvoidmain(字符串[]args){
树集>wsets=新树集>();
for(字符串arg:args){
add(新的WrappedSet(新的TreeSet(Arrays.asList(arg.split(“,”)));
}
System.out.println(“输入集:+Arrays.toString(wsets.toArray()));
}
我知道,如果这个类的.equals()是基于测试各个集合的相等性,那么我的“类[将]具有与equals不一致的自然顺序”,正如它所说的那样。我也理解这可能是输出(有时)不正确的原因。考虑下面的例子:

输入(命令行):A、B、EA、C、F B、D、F A、B、E
输出:输入集:[[A],[A,B,E],[A,C,F],[B,D,F],[A,B,E]]

如您所见,{A,B,E}出现了两次,我想这是因为TreeSet遍历树以查找具有此值的现有条目,但最终没有找到它,因为元素的顺序与它们的实际值无关-仅与它们的大小无关


我如何以一致的方式实现期望的行为?请注意,这不是作业。因此,不基于树集的解决方案自然是受欢迎的。

对于外部的
树集
要接受两个大小相同的不同集合作为不同的元素,您需要确定它们的排序顺序,即使您不关心它们的顺序。否则,您的设置将无法按预期工作

我想我更喜欢编写一个比较器,而不是为内部
TreeSet
s编写一个包装器类。但是要确保比较器在内部集合上定义了一个总的顺序,并且只声明两个集合相等,它们实际上相等,也就是说,它们中只有一个应该在集合中。正如Real怀疑论者和其他人在评论中所说的那样,为了履行
比较器
合同,您需要履行:

实施者必须确保
sgn(比较(x,y))==
-sgn(比较(y,x))
用于所有
x
y

(来自)

这里只是一个非常粗略的比较器示例,当大小相同时,比较器不仅仅比较大小。设计一个仍然做得不够好的例子并不难,但我会让你为你的情况编写一个合适的比较标准

    Comparator<TreeSet<?>> compareBySize 
            = Comparator.comparing((TreeSet<?> s) -> s.size())
                    .thenComparing(TreeSet::toString);

    TreeSet<TreeSet<Character>> mySet = new TreeSet<>(compareBySize);
    mySet.addAll(Arrays.asList(
                new TreeSet<>(Arrays.asList('A', 'B', 'E')),
                new TreeSet<>(Arrays.asList('A', 'C', 'F')),
                new TreeSet<>(Arrays.asList('B', 'D', 'F')),
                new TreeSet<>(Arrays.asList('A')),
                new TreeSet<>(Arrays.asList('A', 'B', 'E'))
            ));
    System.out.println(mySet);
我相信这是正确的

另一方面,通常建议编程时面向接口,而不是实现。如果要执行此操作,请根据您的进一步要求,使用
SortedSet
NavigableSet
界面。您需要两个更改:首先,比较器应该是(在我的示例中使用
SortedSet
):


Comparator对于外部
TreeSet
要接受两个大小相同的不同集合作为不同的元素,您需要确定它们的排序顺序,即使您不关心它们的顺序。否则,您的设置将无法按预期工作

我想我更喜欢编写一个比较器,而不是为内部
TreeSet
s编写一个包装器类。但是要确保比较器在内部集合上定义了一个总的顺序,并且只声明两个集合相等,它们实际上相等,也就是说,它们中只有一个应该在集合中。正如Real怀疑论者和其他人在评论中所说的那样,为了履行
比较器
合同,您需要履行:

实施者必须确保
sgn(比较(x,y))==
-sgn(比较(y,x))
用于所有
x
y

(来自)

这里只是一个非常粗略的比较器示例,当大小相同时,比较器不仅仅比较大小。设计一个仍然做得不够好的例子并不难,但我会让你为你的情况编写一个合适的比较标准

    Comparator<TreeSet<?>> compareBySize 
            = Comparator.comparing((TreeSet<?> s) -> s.size())
                    .thenComparing(TreeSet::toString);

    TreeSet<TreeSet<Character>> mySet = new TreeSet<>(compareBySize);
    mySet.addAll(Arrays.asList(
                new TreeSet<>(Arrays.asList('A', 'B', 'E')),
                new TreeSet<>(Arrays.asList('A', 'C', 'F')),
                new TreeSet<>(Arrays.asList('B', 'D', 'F')),
                new TreeSet<>(Arrays.asList('A')),
                new TreeSet<>(Arrays.asList('A', 'B', 'E'))
            ));
    System.out.println(mySet);
我相信这是正确的

另外,一般建议对towa进行编程
[[A], [A, B, E], [A, C, F], [B, D, F]]
    Comparator<SortedSet<?>> compareBySize 
            = Comparator.comparing((SortedSet<?> s) -> s.size())
                    .thenComparing(SortedSet::toString);