开发者

A subset of a sortedset in Groovy (or Java)

Have a SortedSet where I need a specific slice of records based on a specific element in the list.

Example: In the code below, challengeDTO.members is a SortedSet (TreeSet implementation)

I know the location of one member

def memberRank = 开发者_StackOverflowchallengeDTO.members.findIndexOf { it.member.id == membership?.id} + 1

If the memberRank is 66, I want to get a slice of members 60 through 70 ranks.

challengeDTO.members[60..69] won't work because it's a set

Ideas? Suggestions?

Member implementation:

class ChallengeMemberDTO implements Comparable<ChallengeMemberDTO> {

  ChallengeMember member
  Integer total
  String name
  String teamName

  int compareTo(ChallengeMemberDTO t) {
    if (total == t.total) {  // the sortedset will remove duplicates based on same total, which is not desireable
      return name.compareTo(t.name)
    }
    else {
      return t.total.compareTo(total)
    }
  }
}


Try:

(challengeDTO.members as List)[60..69]

Under the covers the Groovy as List type conversion creates an instance of ArrayList and calls addAll, passing your SortedSet. As per the java.util.List JavaDoc addAll "appends all of the elements in the specified collection to the end of this list, in the order that they are returned by the specified collection's iterator". In the java.util.SortedSet JavaDoc it states that "the set's iterator will traverse the set in ascending element order."

So the order of the list will match the order of the SortedSet.

If you're interested, you can take a look at the method in the Groovy source code:

org.codehaus.groovy.runtime.DefaultGroovyMethods.asList(Collection<T> self)

EDIT:

For the sake completeness, in Java you could do the following. It's just what the Groovy code above does under the covers:

SortedSet<ChallendMemberDTO> memberSet = challengeDTO.getMembers();
List<ChallengeMemberDTO> membersPage = new ArrayList<ChallengeMemberDTO>(memberSet).subList(60, 70);


Well, for that, you have to understand how SortedSet works.

Items that can be used in methods of SortedSet are all those for which the compare() method of the Comparator or the compareTo() method of the items will return a numeric value.

As a consequence, if the compareTo() implementation of your member class allows you to compare members to a number, you can use simply

challengeDTO.members.subSet(60, 70)


SortedSet<E> has the headSet(E), tailSet(E)and subSet(E, E) methods for this purpose.

Just pass in a variable that compares correctly with the values you want:

Sample class:

public class Member implements Comparable<Member>{

    public Member(final int value){  this.value = value; }
    private final int value;
    public int getValue(){ return value; }

    @Override public int hashCode(){ return 31 * value; }

    @Override public boolean equals(final Object obj){
        return obj instanceof Member && ((Member) obj).value == value;
    }

    @Override public String toString(){ "[Member, value="+value+"]"; }

    @Override public int compareTo(final Member o){
        return Integer.valueOf(value).compareTo(Integer.valueOf(o.value));
    }
}

Sample code:

public static void main(final String[] args){
    final SortedSet<Member> set = new TreeSet<Member>();
    for(int i = 0; i < 10; i++){
        set.add(new Member(i));
    }
    System.out.println("TailSet(7): " + set.tailSet(new Member(7)));
    System.out.println("HeadSet(3): " + set.headSet(new Member(3)));
    System.out.println("SubSet(6, 8): " + 
                          set.subSet(new Member(6), new Member(8)));
}

Output:

TailSet(7): [[Member, value=7], [Member, value=8], [Member, value=9]]
HeadSet(3): [[Member, value=0], [Member, value=1], [Member, value=2]]
SubSet(6, 8): [[Member, value=6], [Member, value=7]]


And here's a method that builds the slice (using the NavigableSet interface, which is a superset of SortedSet and also implemented by TreeSet):

public static <K> List<K> slice(final NavigableSet<K> set,
    final K reference,
    final int elementsBefore,
    final int elementsAfter){
    final List<K> list = new ArrayList<K>();
    final Iterator<K> headIterator =
        set.headSet(reference, false).descendingIterator();
    int headCt = 0;
    while(headIterator.hasNext() && headCt++ < elementsBefore){
        list.add(0, headIterator.next());
    }
    list.add(reference);
    final Iterator<K> tailIterator =
        set.tailSet(reference, false).iterator();
    int tailCt = 0;
    while(tailIterator.hasNext() && tailCt++ < elementsAfter){
        list.add(tailIterator.next());
    }

    return list;
}

Usage:

final NavigableSet<Member> set = new TreeSet<Member>();
for(int i = 0; i < 100; i++){
    set.add(new Member(i));
}
System.out.println(slice(set, new Member(67), 2, 2));
System.out.println(slice(set, new Member(2), 25, 2));

Output:

[[Member, value=65], [Member, value=66], [Member, value=67], [Member, value=68], [Member, value=69]]
[[Member, value=0], [Member, value=1], [Member, value=2], [Member, value=3], [Member, value=4]]

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜