我正在寻找一种对一组集合进行排序的方法 - 更具体地说,数据结构需要具有以下属性:
我的基本方法是TreeSet<TreeSet<T>>
,但由于包含的TreeSet需要按自定义行为进行排序,因此我编写了一个包装类(省略了不必要的细节,例如其他构造函数和方法):
import java.util.TreeSet;
import java.util.Iterator;
import java.util.Collection;
public class WrappedSet< T > implements Comparable< WrappedSet< T >>, Iterable< T > {
protected TreeSet< T > set;
public WrappedSet( Collection< T > collection ) {
set = new TreeSet< T >( collection );
}
public int size() {
return set.size();
}
@Override
public Iterator< T > iterator() {
return set.iterator();
}
@Override
public int compareTo( WrappedSet< T > other ) {
if ( set.equals( other.set )) {
return 0;
}
else {
return ( set.size() >= other.set.size()) ? 1 : -1;
}
}
@Override
public String toString() {
return 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()));
}
我理解如果这个类的.equals()基于测试各个集合的相等性,那么我的&#34;类[将]具有与equals&#34; <不一致的自然顺序/ em>,作为CompareTo documentation短语。我也明白这可能是输出(有时)不正确的原因。请考虑以下示例:
输入(命令行):A,B,E A,C,F B,D,F A A,B,E
输出:输入集:[[A],[A,B,E],[A,C,F],[B,D,F],[A,B,E]] < / p>
正如您所看到的,{A,B,E}出现两次,我想这是因为TreeSet遍历树以查找具有此值的现有条目,但最终因为顺序而找不到它元素的独立性与实际值无关 - 只有它们的大小。
我怎样才能以一致的方式实现理想的行为?请注意,这是不作业。因此,不基于TreeSet的解决方案自然受到欢迎。
答案 0 :(得分:0)
为了让你的外TreeSet
接受两个与不同元素大小相同的不同集,你需要确定它们的排序顺序,即使你不关心它们的顺序。否则你的设置将无法按预期工作。
而不是内部TreeSet
的包装类我认为我更喜欢只写一个比较器。但是要确保你的比较器在内部集合上定义了一个总排序,并且只声明两个集合等于它们确实相等,因为它们中只有一个应该在集合中。正如RealSkeptic和其他人在评论中所说,为了履行Comparator
合同,您需要履行:
实施者必须确保所有
sgn(compare(x, y)) == -sgn(compare(y, x))
和x
都y
。
这只是Comparator
的一个非常粗略的例子,当大小相同时,它不仅仅是比较大小。设计一个仍然不能很好的例子并不难,但我会留给你为你的情况写出正确的比较器。
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);
打印
[[A], [A, B, E], [A, C, F], [B, D, F]]
我认为这是正确的。
顺便说一句,通常建议对接口而不是实现进行编程。如果您想这样做,请根据您的进一步要求使用SortedSet
或NavigableSet
界面。您需要进行两项更改:首先,比较器应该是(在我的示例中使用SortedSet
):
Comparator<SortedSet<?>> compareBySize
= Comparator.comparing((SortedSet<?> s) -> s.size())
.thenComparing(SortedSet::toString);
其次将您的设置声明为SortedSet<SortedSet<Character>> mySet
,但仍然在实例化中使用new TreeSet<>(…)
。