2010-02-22 176 views
27

假设我有一个表(或一组):筛选和排序列表

List<String> testList = Lists.newArrayList("assocX","srcT","destA","srcX", "don't care Y", "garbage", "srcB"); 

我想找回一个ImmutableList(集),在自然顺序排序/组方面,其中字词开始“src”是第一个,“assoc”第二个和“dest”最后一个。如果一个术语不包含那些,那么它应该从结果列表中删除。

因此,这里的结果是“srcB”,“srcT”,“assocX”,“destA”。

我想我可以用Iterables.filter或Predicates的组合来做到这一点,但只是没有看到它。我认为必须有一个简洁的方式来做到这一点。

编辑:一组代替列表的作品以及。

回答

32

只要这三个前缀是您所关心的唯一的事情,我建议是这样的:

Predicate<String> filter = new Predicate<String>() { 
     @Override 
     public boolean apply(String input) { 
      return input.startsWith("src") || input.startsWith("assoc") || input.startsWith("dest"); 
     } 
    }; 

    Function<String, Integer> assignWeights = new Function<String, Integer>() { 
     @Override 
     public Integer apply(String from) { 
      if (from.startsWith("src")) { 
       return 0; 
      } else if (from.startsWith("assoc")) { 
       return 1; 
      } else if (from.startsWith("dest")) { 
       return 2; 
      } else { 
       /* Shouldn't be possible but have to do something */ 
       throw new IllegalArgrumentException(from + " is not a valid argument"); 
      } 
     } 
    }; 

    ImmutableList<String> sortedFiltered = ImmutableList.copyOf(
      Ordering.natural().onResultOf(assignWeights).sortedCopy(
        Iterables.filter(testList, filter) 
      ) 
    ); 

这个解决方案绝对不会向外扩展令人难以置信的好,如果你开始增加更多的前缀过滤或排序,因为您必须不断更新过滤器和每个前缀的权重。

+11

在其他情况下,抛出新的IllegalArgumentException()比'return 3'更好。 – 2011-09-30 11:42:50

0

我想你会首先使用谓词来消除你不想要的元素,然后执行一个Comparator并对你的列表进行排序。

12

看一看This Google Collections example

Function<Fruit, String> getNameFunction = new Function<Fruit, String>() { 
    public String apply(Fruit from) { 
     return from.getName(); 
    } 
}; 

Ordering<Fruit> nameOrdering = Ordering.natural().onResultOf(getNameFunction); 

ImmutableSortedSet<Fruit> sortedFruits = ImmutableSortedSet.orderedBy(
    nameOrdering).addAll(fruits).build(); 

尽管这肯定会返回一个Set。

0

通常这是很糟糕的设计来整理清晰的数据,像这样。在你的情况下,当你说“assocX”时,“assoc”与“X”有不同的含义,但是你将它们合并在一起。

所以我建议设计一个有两个字段的类。然后,您可以在第一个字段上创建排序,在第二个字段上创建另一个排列,并将它们合并(例如Ordering#compound())。使用确实的toString()方法将这些字段合并为一个字符串。作为奖励,这可能通过共享大大减少内存使用量。

所以你会排序这些对象的列表,如果你想打印它们,你只需在它们上面调用toString()。