开发者

how to selectively filter items in a collection

开发者 https://www.devze.com 2022-12-30 06:39 出处:网络
I use the following snippet to filter the list of selected users, where isSelected is a boolean variable. Is there a simpler way (h开发者_运维百科elper function) to populate the selectedUsers collecti

I use the following snippet to filter the list of selected users, where isSelected is a boolean variable. Is there a simpler way (h开发者_运维百科elper function) to populate the selectedUsers collection instead of writing the following lines of code.

List<User> selectedUsers = new ArrayList<User>(0);
for (User user : this.getUsers()) {
    if (user.isSelected()) {
        selectedUsers.add(user.getId());
    }
}


You can use the filter function from the Google Collections; however, you will still need to construct a predicate object, and if you want to manipulate the result, you will have to construct another collection and pass the result in, since the result of filter is an immutable filtered view of the original collection.

To make this more concrete:

List<User> selectedUsers = new ArrayList<User>(
           Iterables.filter(
                  this.getUsers(),
                  new Predicate<User>()
                      {
                          public boolean apply(User usr){ 
                                return usr.isSelected();
                          }
                       }
           ));

Of course, this is not really that much cleaner (unless you make a separate class for your predicate and happen to reuse it in a bunch of places), and it actually returns the list of users, not their IDs... you would have to use a "transform" to get their IDs, so personally, I would just go with what you have now.


Following Michael's answer, Apache common's CollectionUtils has a [filter][1] methods too

[1]: http://commons.apache.org/collections/api-2.1.1/org/apache/commons/collections/CollectionUtils.html#filter(java.util.Collection, org.apache.commons.collections.Predicate)


An alternative to filtering would be to maintain the list of selected users. In setSelected(true) you could add a user to the list and use setSelected(false) to remove it.

class User {
   List<User> selectedUsers = new ArrayList<User>(0); 

   void setSelected(boolean isSelected) {
        if ( isSelected) {
           selectedUsers.add(user.getId()); 
        }
        else {
            int idx = selectedUsers.indexOf( this );
            if ( idx >= 0 )
                selectedUsers.remove( idx );
        }
    } 
} 

This aproach requires an implemented equals method. BTW your snippet adds the userId (Int?) to the list of type User.


You could write your own code for it, which would save you a few lines of code in every place where you apply a filter (at the cost of more code in a util class). Your call whether it's worth it or not...

In one place:

  public interface Filter<T> {
    boolean select(T t);
  } 

  public static <E> List<E> select(Collection<? extends E> es, Filter<? super E> filter) {
    final List<E> result = new ArrayList<E>();
    for (E e : es) {
      if (filter.select(e)) {
        result.add(e);
      }
    }
    return result;
  }

And the predicate:

  private static class Filter<User> selectedUserFilter = new Filter<User>() {
    public boolean select(User user) {
      return user.isSelected();
    }
  };

Aaaand:

   final List<User> selectedUsers = Util.select(this.getUsers(), selectedUserFilter);

Again, you end up with only one line of code at the end, at the cost of more code in other places.


You could use a different approach: If possible, just build up your selectedUsers list when a user is being selected. IIRC that is called over eager evaluation - that means, you provide this "calculation" when a selection status changed, not afterwards. Without context I can't say if it is a good way for you. But in some cases it is good because you don't have to iterate through a (maybe) long list.

0

精彩评论

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