Cách tốt nhất để lọc Bộ sưu tập Java là gì?


Câu trả lời:


698

Java 8 ( 2014 ) giải quyết vấn đề này bằng cách sử dụng các luồng và lambdas trong một dòng mã:

List<Person> beerDrinkers = persons.stream()
    .filter(p -> p.getAge() > 16).collect(Collectors.toList());

Đây là một hướng dẫn .

Sử dụng Collection#removeIfđể sửa đổi bộ sưu tập tại chỗ. (Lưu ý: Trong trường hợp này, vị từ sẽ loại bỏ các đối tượng thỏa mãn vị ngữ):

persons.removeIf(p -> p.getAge() <= 16);

lambdaj cho phép lọc các bộ sưu tập mà không cần viết các vòng lặp hoặc các lớp bên trong:

List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
    greaterThan(16)));

Bạn có thể tưởng tượng một cái gì đó dễ đọc hơn?

Tuyên bố miễn trừ trách nhiệm: Tôi là người đóng góp cho lambdaj


34
Đẹp nhưng nhập khẩu tĩnh làm xáo trộn những gì đang xảy ra. Để tham khảo, chọn / có / bật là nhập tĩnh trên ch.lambdaj.Lambda, GreaterThan là org.hamcrest.Matchers
MikePatel

11
LambdaJ thực sự rất gợi cảm, nhưng đáng chú ý là nó bao hàm một chi phí đáng kể (trung bình 2,6): code.google.com/p/lambdaj/wiki/PerformanceAnalysis .
Doc Davluz

7
Rõ ràng không hoạt động trên Android: Groups.google.com/forum/#!msg/lambdaj/km7uFgvSd3k/grJhgl3ik5sJ
Moritz

7
Thực sự thích ví dụ này của LamdaJ ... tương tự như các hàm Lambda tích hợp sẵn .NET. Và một người có thể uống ở đâu khi 16 tuổi? Chúng ta nên xem xét thêm một ràng buộc nội địa hóa. : P
MAbraham1

3
loại bỏ ví dụ nên làpersons.removeIf(p -> p.getAge() <= 16);
vim

223

Giả sử rằng bạn đang sử dụng Java 1.5 và bạn không thể thêm Bộ sưu tập của Google , tôi sẽ làm một cái gì đó rất giống với những gì Google đã làm. Đây là một thay đổi nhỏ về ý kiến ​​của Jon.

Đầu tiên thêm giao diện này vào cơ sở mã của bạn.

public interface IPredicate<T> { boolean apply(T type); }

Những người thực hiện nó có thể trả lời khi một vị ngữ nhất định đúng với một loại nhất định. Ví dụ: Nếu Tđã UserAuthorizedUserPredicate<User>thực hiện IPredicate<T>, sau đó AuthorizedUserPredicate#applytrả về cho dù thông qua Userđược cho phép.

Sau đó, trong một số lớp tiện ích, bạn có thể nói

public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
    Collection<T> result = new ArrayList<T>();
    for (T element: target) {
        if (predicate.apply(element)) {
            result.add(element);
        }
    }
    return result;
}

Vì vậy, giả sử rằng bạn có việc sử dụng ở trên có thể là

Predicate<User> isAuthorized = new Predicate<User>() {
    public boolean apply(User user) {
        // binds a boolean method in User to a reference
        return user.isAuthorized();
    }
};
// allUsers is a Collection<User>
Collection<User> authorizedUsers = filter(allUsers, isAuthorized);

Nếu hiệu suất của kiểm tra tuyến tính là mối quan tâm, thì tôi có thể muốn có một đối tượng miền có bộ sưu tập đích. Đối tượng miền có bộ sưu tập đích sẽ có logic lọc cho các phương thức khởi tạo, thêm và đặt bộ sưu tập đích.

CẬP NHẬT:

Trong lớp tiện ích (giả sử là Vị ngữ), tôi đã thêm một phương thức chọn với một tùy chọn cho giá trị mặc định khi vị từ không trả về giá trị mong đợi và cũng là một thuộc tính tĩnh cho các tham số được sử dụng bên trong IPredicate mới.

public class Predicate {
    public static Object predicateParams;

    public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
        Collection<T> result = new ArrayList<T>();
        for (T element : target) {
            if (predicate.apply(element)) {
                result.add(element);
            }
        }
        return result;
    }

    public static <T> T select(Collection<T> target, IPredicate<T> predicate) {
        T result = null;
        for (T element : target) {
            if (!predicate.apply(element))
                continue;
            result = element;
            break;
        }
        return result;
    }

    public static <T> T select(Collection<T> target, IPredicate<T> predicate, T defaultValue) {
        T result = defaultValue;
        for (T element : target) {
            if (!predicate.apply(element))
                continue;
            result = element;
            break;
        }
        return result;
    }
}

Ví dụ sau đây tìm kiếm các đối tượng bị thiếu giữa các bộ sưu tập:

List<MyTypeA> missingObjects = (List<MyTypeA>) Predicate.filter(myCollectionOfA,
    new IPredicate<MyTypeA>() {
        public boolean apply(MyTypeA objectOfA) {
            Predicate.predicateParams = objectOfA.getName();
            return Predicate.select(myCollectionB, new IPredicate<MyTypeB>() {
                public boolean apply(MyTypeB objectOfB) {
                    return objectOfB.getName().equals(Predicate.predicateParams.toString());
                }
            }) == null;
        }
    });

Ví dụ sau, tìm kiếm một thể hiện trong một bộ sưu tập và trả về phần tử đầu tiên của bộ sưu tập làm giá trị mặc định khi không tìm thấy thể hiện:

MyType myObject = Predicate.select(collectionOfMyType, new IPredicate<MyType>() {
public boolean apply(MyType objectOfMyType) {
    return objectOfMyType.isDefault();
}}, collectionOfMyType.get(0));

CẬP NHẬT (sau khi phát hành Java 8):

Đã vài năm kể từ lần đầu tiên tôi (Alan) đăng câu trả lời này và tôi vẫn không thể tin rằng mình đang thu thập điểm SO cho câu trả lời này. Ở mức độ nào, bây giờ Java 8 đã giới thiệu các bao đóng cho ngôn ngữ, câu trả lời của tôi bây giờ sẽ khác đi đáng kể và đơn giản hơn. Với Java 8, không cần một lớp tiện ích tĩnh riêng biệt. Vì vậy, nếu bạn muốn tìm phần tử thứ 1 phù hợp với vị ngữ của bạn.

final UserService userService = ... // perhaps injected IoC
final Optional<UserModel> userOption = userCollection.stream().filter(u -> {
    boolean isAuthorized = userService.isAuthorized(u);
    return isAuthorized;
}).findFirst();

API JDK 8 cho optionals có khả năng get(), isPresent(), orElse(defaultUser), orElseGet(userSupplier)orElseThrow(exceptionSupplier), cũng như các chức năng khác 'monadic' như map, flatMapfilter.

Nếu bạn chỉ muốn thu thập tất cả người dùng phù hợp với vị ngữ, thì hãy sử dụng Collectorsđể kết thúc luồng trong bộ sưu tập mong muốn.

final UserService userService = ... // perhaps injected IoC
final List<UserModel> userOption = userCollection.stream().filter(u -> {
    boolean isAuthorized = userService.isAuthorized(u);
    return isAuthorized;
}).collect(Collectors.toList());

Xem ở đây để biết thêm ví dụ về cách hoạt động của luồng Java 8.


27
Vâng, nhưng tôi ghét phải phát minh lại bánh xe, một lần nữa, lặp đi lặp lại. Tôi muốn tìm một số thư viện tiện ích mà tôi muốn.
Kevin Wong

2
Đây không phải là cách tốt nhất trong trường hợp bạn không muốn bộ sưu tập mới. Sử dụng phép ẩn dụ bộ lọc lặp, có thể nhập vào bộ sưu tập mới hoặc có thể là tất cả những gì bạn cần.
Josh

@Nestor: theo cách hiểu của Scala, việc lọc sẽ đơn giản hơn nhiều:val authorized = for (user <- users if user.isAuthorized) yield user
Alan

Điều này có sửa đổi bộ sưu tập ban đầu hoặc tạo ra một thương hiệu mới? Tôi đã thử sử dụng phương thức này và ghi lại cả các bộ sưu tập của tôi (bản gốc và bộ sưu tập được trả về từ phương thức), chúng giống nhau. @Alan
Rohan

1
@Rohan, điều này không có nghĩa là làm thay đổi bộ sưu tập ban đầu. Lưu ý rằng bộ sưu tập kết quả ở trên được xây dựng mới và phương thức bộ lọc chỉ thêm vào bộ sưu tập kết quả nếu áp dụng vị ngữ.
Alan

92

Sử dụng CollectionUtils.filter (Bộ sưu tập, Vị ngữ) , từ Apache Commons.


3
Điều này không sao, nhưng nó không chung chung, và sửa đổi bộ sưu tập tại chỗ (không đẹp)
Kevin Wong

2
Có các phương thức lọc khác trong CollectionUtils không sửa đổi bộ sưu tập gốc.
skaffman

42
Cụ thể, phương pháp không sửa đổi bộ sưu tập tại chỗ là org.apache.commons.collections.CollectionUtils # select (Bộ sưu tập, Dự đoán)
Eero

5
Trong Commons Collection Collection v4 giờ đây sử dụng Generics.
Justin Emery

1
Phương pháp này nên được sử dụng một cách thận trọng vì nó phụ thuộc (ít nhất là trong việc thực hiện commons-sưu tập-3.2.1) trên phương thức iterator.remove () là tùy chọn cho các bộ sưu tập, vì vậy thay vì lọc, giả sử là một mảng, bạn có thể nhận được một UnceptionedOperationException.
dùng2417480

67

Cách "tốt nhất" là một yêu cầu quá rộng. Có phải là "ngắn nhất"? "Nhanh nhất"? "Có thể đọc được"? Lọc tại chỗ hoặc vào bộ sưu tập khác?

Cách đơn giản nhất (nhưng không dễ đọc nhất) là lặp lại nó và sử dụng phương thức Iterator.remove ():

Iterator<Foo> it = col.iterator();
while( it.hasNext() ) {
  Foo foo = it.next();
  if( !condition(foo) ) it.remove();
}

Bây giờ, để làm cho nó dễ đọc hơn, bạn có thể gói nó thành một phương thức tiện ích. Sau đó, phát minh ra một giao diện IPredicate, tạo một triển khai ẩn danh của giao diện đó và làm một cái gì đó như:

CollectionUtils.filterInPlace(col,
  new IPredicate<Foo>(){
    public boolean keepIt(Foo foo) {
      return foo.isBar();
    }
  });

trong đó filterInPlace () lặp lại bộ sưu tập và gọi Primateate.keepIt () để tìm hiểu nếu cá thể được giữ trong bộ sưu tập.

Tôi thực sự không thấy một lời biện minh nào cho việc mang vào thư viện của bên thứ ba chỉ cho nhiệm vụ này.


6
Phiếu bầu của tôi dành cho cái này: nó chỉ hoạt động, không có thư viện bên ngoài. Tôi chưa bao giờ nhận ra việc khởi tạo một Iterator thực sự có thể hữu ích so với việc sử dụng cú pháp cho từng cú pháp hoặc rằng bạn có thể xóa các mục khỏi danh sách mà không cần có ConcurrencyModificationException hoặc đại loại như thế. :)
ZeroOne

1
Tôi nghĩ rằng đây là cách tốt nhất để sử dụng lib Java tiêu chuẩn mà không cần sao chép. Đối với phiên bản 1.8 sẽ có stream()tính năng này, nhưng không phải ai cũng được chơi với những đồ chơi mới nhất: P
Populus

Điều này có sửa đổi bộ sưu tập ban đầu quá không? @ZeroOne
Rohan

Vâng tất nhiên là có, @Rohan. Hãy thử nếu bạn không tin. ;)
ZeroOne 15/03/2016

Haha tôi đã làm Nhưng tôi muốn giữ lại bộ sưu tập ban đầu của mình. Bạn có thể đề xuất một cách để làm điều này mà không cần thêm một lib bên ngoài? @ZeroOne
Rohan

62

Xem xét Bộ sưu tập của Google cho khung Bộ sưu tập được cập nhật hỗ trợ thuốc generic.

CẬP NHẬT : Thư viện bộ sưu tập google hiện không dùng nữa. Thay vào đó, bạn nên sử dụng phiên bản mới nhất của Guava . Nó vẫn có tất cả các phần mở rộng giống nhau cho khung bộ sưu tập bao gồm cơ chế lọc dựa trên một vị từ.


ya, tôi biết về bộ sưu tập lib của Google. Phiên bản tôi đang sử dụng không có Bộ sưu tập2 trong đó. Tôi đã thêm một câu trả lời mới cho câu hỏi này liệt kê phương pháp cụ thể.
Kevin Wong

7
Kevin, Iterables.filter () và Iterators.filter () đã ở đó từ đầu và thường là tất cả những gì bạn cần.
Kevin Bourrillion

28

Đợi Java 8:

List<Person> olderThan30 = 
  //Create a Stream from the personList
  personList.stream().
  //filter the element to select only those with age >= 30
  filter(p -> p.age >= 30).
  //put those filtered elements into a new List.
  collect(Collectors.toList());

13
Ugh ... thật dài dòng. Tại sao họ không thể làm: Liệt kê <Person> result = personList.filter (p -> p.age> 30);
Kevin Wong

8
Để sử dụng bộ lọc trực tiếp trên Collection bạn cần sử dụng removeIf gọi: download.java.net/jdk8/docs/api/java/util/...
gavenkoa

6
@KevinWong "verbose" khá nhiều mô tả toàn bộ ngôn ngữ tôi sẽ nghĩ. Ít nhất là họ nhất quán?
Rogue

5
Tại sao không sử dụng Collector.toList () trong phần cuối?
Nestor Hernandez Loli

3
Đây là một liên kết gavenkoa cung cấp mà không 404. personList.removeIf(p -> p.age < 30);Ít dài dòng hơn. Ngoài ra, tôi đã nghe nói về việc bắt đầu thực hiện apis chấp nhận và trả lại Streams thay vì Collections vì Streamnó rất hữu ích và nhanh chóng nhưng việc đi đến / từ chúng là chậm.
Thuyền trưởng Man

11

Kể từ khi phát hành sớm Java 8, bạn có thể thử một cái gì đó như:

Collection<T> collection = ...;
Stream<T> stream = collection.stream().filter(...);

Ví dụ: nếu bạn có một danh sách các số nguyên và bạn muốn lọc các số> 10 và sau đó in ra các số đó vào bảng điều khiển, bạn có thể thực hiện một số việc như:

List<Integer> numbers = Arrays.asList(12, 74, 5, 8, 16);
numbers.stream().filter(n -> n > 10).forEach(System.out::println);

11

Tôi sẽ ném RxJava vào vòng, cũng có sẵn trên Android . RxJava có thể không phải luôn luôn là lựa chọn tốt nhất, nhưng nó sẽ giúp bạn linh hoạt hơn nếu bạn muốn thêm nhiều biến đổi trên bộ sưu tập của mình hoặc xử lý các lỗi trong khi lọc.

Observable.from(Arrays.asList(1, 2, 3, 4, 5))
    .filter(new Func1<Integer, Boolean>() {
        public Boolean call(Integer i) {
            return i % 2 != 0;
        }
    })
    .subscribe(new Action1<Integer>() {
        public void call(Integer i) {
            System.out.println(i);
        }
    });

Đầu ra:

1
3
5

Thông tin chi tiết về RxJava filtercó thể được tìm thấy ở đây .


7

Các thiết lập:

public interface Predicate<T> {
  public boolean filter(T t);
}

void filterCollection(Collection<T> col, Predicate<T> predicate) {
  for (Iterator i = col.iterator(); i.hasNext();) {
    T obj = i.next();
    if (predicate.filter(obj)) {
      i.remove();
    }
  }
}

Việc sử dụng:

List<MyObject> myList = ...;
filterCollection(myList, new Predicate<MyObject>() {
  public boolean filter(MyObject obj) {
    return obj.shouldFilter();
  }
});

2
Tốt, nhưng tôi thích triển khai Alan hơn vì bạn nhận được một bản sao của bộ sưu tập thay vì thay đổi nó. Hơn nữa, mã của Alan là luồng an toàn trong khi mã của bạn thì không.
marcospereira

7

Làm thế nào về một số Java đơn giản và mạnh mẽ

 List<Customer> list ...;
 List<Customer> newList = new ArrayList<>();
 for (Customer c : list){
    if (c.getName().equals("dd")) newList.add(c);
 }

Đơn giản, dễ đọc và dễ dàng (và hoạt động trong Android!) Nhưng nếu bạn đang sử dụng Java 8, bạn có thể thực hiện điều đó trong một dòng ngọt ngào:

List<Customer> newList = list.stream().filter(c -> c.getName().equals("dd")).collect(toList());

Lưu ý rằng toList () được nhập tĩnh



7

Hãy xem cách lọc Danh sách JDK tích hợp và Danh sách Mutable bằng cách sử dụng Bộ sưu tập Eclipse .

List<Integer> jdkList = Arrays.asList(1, 2, 3, 4, 5);
MutableList<Integer> ecList = Lists.mutable.with(1, 2, 3, 4, 5);

Nếu bạn muốn lọc các số nhỏ hơn 3, bạn sẽ mong đợi các đầu ra sau.

List<Integer> selected = Lists.mutable.with(1, 2);
List<Integer> rejected = Lists.mutable.with(3, 4, 5);

Đây là cách bạn có thể lọc bằng lambda Java 8 như Predicate.

Assert.assertEquals(selected, Iterate.select(jdkList, each -> each < 3));
Assert.assertEquals(rejected, Iterate.reject(jdkList, each -> each < 3));

Assert.assertEquals(selected, ecList.select(each -> each < 3));
Assert.assertEquals(rejected, ecList.reject(each -> each < 3));

Đây là cách bạn có thể lọc bằng cách sử dụng một lớp bên trong ẩn danh là Predicate.

Predicate<Integer> lessThan3 = new Predicate<Integer>()
{
    public boolean accept(Integer each)
    {
        return each < 3;
    }
};

Assert.assertEquals(selected, Iterate.select(jdkList, lessThan3));
Assert.assertEquals(selected, ecList.select(lessThan3));

Dưới đây là một số lựa chọn thay thế để lọc danh sách JDK và Bộ sưu tập Eclipse MutableLists bằng cách sử dụng nhà máy Dự đoán .

Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));
Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));

Đây là một phiên bản không phân bổ một đối tượng cho vị từ, bằng cách sử dụng nhà máy Dự đoán2 thay vì selectWithphương thức lấy một Predicate2.

Assert.assertEquals(
    selected, ecList.selectWith(Predicates2.<Integer>lessThan(), 3));

Đôi khi bạn muốn lọc trên một điều kiện tiêu cực. Có một phương thức đặc biệt trong Bộ sưu tập Eclipse cho cái được gọi đó reject.

Assert.assertEquals(rejected, Iterate.reject(jdkList, lessThan3));
Assert.assertEquals(rejected, ecList.reject(lessThan3));

Phương thức partitionsẽ trả về hai bộ sưu tập, chứa các phần tử được chọn và từ chối bởi Predicate.

PartitionIterable<Integer> jdkPartitioned = Iterate.partition(jdkList, lessThan3);
Assert.assertEquals(selected, jdkPartitioned.getSelected());
Assert.assertEquals(rejected, jdkPartitioned.getRejected());

PartitionList<Integer> ecPartitioned = gscList.partition(lessThan3);
Assert.assertEquals(selected, ecPartitioned.getSelected());
Assert.assertEquals(rejected, ecPartitioned.getRejected());

Lưu ý: Tôi là người đi làm cho Bộ sưu tập Eclipse.


1
Làm thế nào bạn sẽ làm removeIfmột danh sách hoặc thiết lập cho nguyên thủy?
Vivek Rao

API cho remove If đã được thêm vào các bộ sưu tập nguyên thủy trong EC 9.1. eclipse.org/collections/javadoc/9.1.0/org/eclipse/collections/ khăn
Donald Raab

5

Với DSL ForEach bạn có thể viết

import static ch.akuhn.util.query.Query.select;
import static ch.akuhn.util.query.Query.$result;
import ch.akuhn.util.query.Select;

Collection<String> collection = ...

for (Select<String> each : select(collection)) {
    each.yield = each.value.length() > 3;
}

Collection<String> result = $result();

Đưa ra một bộ sưu tập [The, quick, brown, fox, jumps, over, the, lazy, dog] điều này dẫn đến [quick, brown, jumps, over, lazy], tức là tất cả các chuỗi dài hơn ba ký tự.

Tất cả các kiểu lặp được hỗ trợ bởi ForEach DSL là

  • AllSatisfy
  • AnySatisfy
  • Collect
  • Counnt
  • CutPieces
  • Detect
  • GroupedBy
  • IndexOf
  • InjectInto
  • Reject
  • Select

Để biết thêm chi tiết, vui lòng tham khảo https://www.iam.unibe.ch/scg/svn_Vpose/Source/ForEach


Điều đó khá thông minh! Rất nhiều công việc để thực hiện một cú pháp Ruby-ish đẹp! Điều tiêu cực là bộ lọc của bạn không phải là chức năng hạng nhất và do đó không thể được sử dụng lại. Tiếp tục đóng cửa ...
oxbow_lakes

Điểm tốt. Một cách để sử dụng lại thân vòng lặp là tái cấu trúc vòng lặp thành một phương thức lấy truy vấn lựa chọn làm tham số. Đó là tuy nhiên cho đến nay không tiện dụng và mạnh mẽ như đóng cửa thực sự, chắc chắn.
akuhn


5

java 9 Collectors.filtering được bật:

public static <T, A, R>
    Collector<T, ?, R> filtering(Predicate<? super T> predicate,
                                 Collector<? super T, A, R> downstream)

Do đó, bộ lọc phải là:

collection.stream().collect(Collectors.filtering(predicate, collector))

Thí dụ:

List<Integer> oddNumbers = List.of(1, 19, 15, 10, -10).stream()
            .collect(Collectors.filtering(i -> i % 2 == 1, Collectors.toList()));

3

Điều này, kết hợp với việc thiếu các bao đóng thực sự, là điểm yếu lớn nhất của tôi đối với Java. Thành thật mà nói, hầu hết các phương pháp được đề cập ở trên là khá dễ đọc và THỰC SỰ hiệu quả; tuy nhiên, sau khi dành thời gian với .Net, Erlang, v.v ... danh sách hiểu được tích hợp ở cấp độ ngôn ngữ làm cho mọi thứ trở nên sạch sẽ hơn rất nhiều. Không có bổ sung ở cấp độ ngôn ngữ, Java không thể sạch như nhiều ngôn ngữ khác trong lĩnh vực này.

Nếu hiệu suất là một mối quan tâm lớn, các bộ sưu tập của Google là cách để đi (hoặc viết tiện ích vị ngữ đơn giản của riêng bạn). Cú pháp Lambdaj dễ đọc hơn đối với một số người, nhưng nó không hoàn toàn hiệu quả.

Và sau đó có một thư viện tôi đã viết. Tôi sẽ bỏ qua bất kỳ câu hỏi nào liên quan đến hiệu quả của nó (vâng, nó tệ lắm)

LinkedList<Person> list = ......
LinkedList<Person> filtered = 
           Query.from(list).where(Condition.ensure("age", Op.GTE, 21));

HOẶC LÀ

LinkedList<Person> list = ....
LinkedList<Person> filtered = Query.from(list).where("x => x.age >= 21");

Liên kết? Ngay cả khi thư viện của bạn không hiệu quả hoặc không sử dụng được, nó vẫn có thể thú vị để xem xét nếu nguồn có sẵn.
MatrixFrog

Công khai repo ( net-machine.com/indefero/p/jdclib/source/tree/master ). Bạn quan tâm đến gói biểu thức. Gói thử nghiệm có một thử nghiệm với việc sử dụng ví dụ. Tôi chưa bao giờ thực sự làm việc nhiều với giao diện truy vấn chuỗi được tham chiếu ở trên (không cảm thấy như viết một trình phân tích cú pháp thực sự), vì vậy giao diện truy vấn rõ ràng trong trình kiểm tra là cách để đi.
jdc0589

2

JFilter http://code.google.com.vn/p/jfilter/ phù hợp nhất với yêu cầu của bạn.

JFilter là một thư viện mã nguồn mở đơn giản và hiệu năng cao để truy vấn bộ sưu tập các hạt Java.

Các tính năng chính

  • Hỗ trợ các thuộc tính của bộ sưu tập (java.util.Collection, java.util.Map và Array).
  • Hỗ trợ của bộ sưu tập bên trong bộ sưu tập của bất kỳ độ sâu.
  • Hỗ trợ các truy vấn bên trong.
  • Hỗ trợ các truy vấn tham số.
  • Có thể lọc 1 triệu bản ghi trong vài 100 ms.
  • Bộ lọc (truy vấn) được đưa ra ở định dạng json đơn giản, nó giống như các truy vấn Mangodb. Sau đây là một số ví dụ.
  • {"id": {"$ le": "10"}
    • trong đó thuộc tính id đối tượng nhỏ hơn 10.
  • {"id": {"$ in": ["0", "100"]}}
    • trong đó thuộc tính id đối tượng là 0 hoặc 100.
  • {"lineItems": {"lineAmount": "1"}}
    • trong đó thuộc tính bộ sưu tập lineItems của loại tham số có lineAmount bằng 1.
  • {"$ và": [{"id": "0"}, {"BillingAddress": {"city": "DEL"}}]}
    • trong đó tài sản id là 0 và propertyAddress.city property là DEL.
  • {"lineItems": {"tax": {"key": {"code": "GST"}, "value": {"$ gt": "1.01"}}}}
    • trong đó thuộc tính bộ sưu tập lineItems của loại tham số có thuộc tính loại bản đồ thuế của loại tham số có mã bằng với giá trị GST lớn hơn 1,01.
  • {'$ hoặc': [{'code': '10'}, {'skus': {'$ và': [{'price': {'$ in': ['20', '40']} }, {'mã': 'RedApple'}]}}]}
    • Chọn tất cả các sản phẩm có mã sản phẩm là 10 hoặc giá sku trong 20 và 40 và mã sku là "RedApple".

1
Bạn nên từ chối rằng bạn là tác giả (như tôi nghĩ đó là trường hợp).
assylias

Vâng, tôi là tác giả của thư viện này.
Kamran Ali Khan

2

Tôi đã viết một lớp Iterable mở rộng hỗ trợ áp dụng các thuật toán chức năng mà không cần sao chép nội dung bộ sưu tập.

Sử dụng:

List<Integer> myList = new ArrayList<Integer>(){ 1, 2, 3, 4, 5 }

Iterable<Integer> filtered = Iterable.wrap(myList).select(new Predicate1<Integer>()
{
    public Boolean call(Integer n) throws FunctionalException
    {
        return n % 2 == 0;
    }
})

for( int n : filtered )
{
    System.out.println(n);
}

Đoạn mã trên sẽ thực sự thực thi

for( int n : myList )
{
    if( n % 2 == 0 ) 
    {
        System.out.println(n);
    }
}


2

Một số câu trả lời thực sự tuyệt vời ở đây. Tôi, tôi muốn giữ cho mình đơn giản và dễ đọc nhất có thể:

public abstract class AbstractFilter<T> {

    /**
     * Method that returns whether an item is to be included or not.
     * @param item an item from the given collection.
     * @return true if this item is to be included in the collection, false in case it has to be removed.
     */
    protected abstract boolean excludeItem(T item);

    public void filter(Collection<T> collection) {
        if (CollectionUtils.isNotEmpty(collection)) {
            Iterator<T> iterator = collection.iterator();
            while (iterator.hasNext()) {
                if (excludeItem(iterator.next())) {
                    iterator.remove();
                }
            }
        }
    }
}

Chỉ cần thực hiện các loại trừ thích hợp cho mỗi bộ lọc. Cuối cùng, bạn sẽ có các bộ lọc riêng biệt giống như bạn có bộ sắp xếp trên Bộ sưu tập ...
Lawrence

1

Giải pháp tiền Java8 đơn giản:

ArrayList<Item> filtered = new ArrayList<Item>(); 
for (Item item : items) if (condition(item)) filtered.add(item);

Thật không may, giải pháp này không hoàn toàn chung chung, xuất ra một danh sách hơn là loại bộ sưu tập đã cho. Ngoài ra, việc mang vào các thư viện hoặc viết các hàm bao bọc mã này có vẻ như quá mức cần thiết đối với tôi trừ khi điều kiện phức tạp, nhưng sau đó bạn có thể viết một hàm cho điều kiện.


1

https://code.google.com.vn/p/joquery/

Hỗ trợ các khả năng khác nhau,

Cho bộ sưu tập,

Collection<Dto> testList = new ArrayList<>();

loại,

class Dto
{
    private int id;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getText()
    {
        return text;
    }
}

Bộ lọc

Java 7

Filter<Dto> query = CQ.<Dto>filter(testList)
    .where()
    .property("id").eq().value(1);
Collection<Dto> filtered = query.list();

Java 8

Filter<Dto> query = CQ.<Dto>filter(testList)
    .where()
    .property(Dto::getId)
    .eq().value(1);
Collection<Dto> filtered = query.list();

Cũng thế,

Filter<Dto> query = CQ.<Dto>filter()
        .from(testList)
        .where()
        .property(Dto::getId).between().value(1).value(2)
        .and()
        .property(Dto::grtText).in().value(new string[]{"a","b"});

Sắp xếp (cũng có sẵn cho Java 7)

Filter<Dto> query = CQ.<Dto>filter(testList)
        .orderBy()
        .property(Dto::getId)
        .property(Dto::getName)
    Collection<Dto> sorted = query.list();

Nhóm (cũng có sẵn cho Java 7)

GroupQuery<Integer,Dto> query = CQ.<Dto,Dto>query(testList)
        .group()
        .groupBy(Dto::getId)
    Collection<Grouping<Integer,Dto>> grouped = query.list();

Tham gia (cũng có sẵn cho Java 7)

Được,

class LeftDto
{
    private int id;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getText()
    {
        return text;
    }
}

class RightDto
{
    private int id;
    private int leftId;
    private String text;

    public int getId()
    {
        return id;
    }

    public int getLeftId()
        {
            return leftId;
        }

    public int getText()
    {
        return text;
    }
}

class JoinedDto
{
    private int leftId;
    private int rightId;
    private String text;

    public JoinedDto(int leftId,int rightId,String text)
    {
        this.leftId = leftId;
        this.rightId = rightId;
        this.text = text;
    }

    public int getLeftId()
    {
        return leftId;
    }

    public int getRightId()
        {
            return rightId;
        }

    public int getText()
    {
        return text;
    }
}

Collection<LeftDto> leftList = new ArrayList<>();

Collection<RightDto> rightList = new ArrayList<>();

Có thể tham gia như,

Collection<JoinedDto> results = CQ.<LeftDto, LeftDto>query().from(leftList)
                .<RightDto, JoinedDto>innerJoin(CQ.<RightDto, RightDto>query().from(rightList))
                .on(LeftFyo::getId, RightDto::getLeftId)
                .transformDirect(selection ->  new JoinedDto(selection.getLeft().getText()
                                                     , selection.getLeft().getId()
                                                     , selection.getRight().getId())
                                 )
                .list();

Biểu thức

Filter<Dto> query = CQ.<Dto>filter()
    .from(testList)
    .where()
    .exec(s -> s.getId() + 1).eq().value(2);

1

Câu trả lời của tôi dựa trên điều đó từ Kevin Wong, ở đây dưới dạng một lớp lót sử dụng CollectionUtilstừ mùa xuân và biểu thức lambda Java 8 .

CollectionUtils.filter(list, p -> ((Person) p).getAge() > 16);

Điều này ngắn gọn và dễ đọc như bất kỳ sự thay thế nào tôi đã thấy (không sử dụng các thư viện dựa trên khía cạnh)

Spring CollectionUtils có sẵn từ phiên bản mùa xuân 4.0.2.RELEASE và hãy nhớ rằng bạn cần JDK 1.8 và ngôn ngữ cấp 8+.


1

Sử dụng java 8, cụ thể lambda expression, bạn có thể làm điều đó đơn giản như ví dụ dưới đây:

myProducts.stream().filter(prod -> prod.price>10).collect(Collectors.toList())

trong đó cho mỗi bộ sưu tập productbên trong myProducts, nếu prod.price>10, sau đó thêm sản phẩm này vào danh sách được lọc mới.


1

Tôi cần lọc một danh sách tùy thuộc vào các giá trị đã có trong danh sách. Ví dụ: xóa tất cả các giá trị theo sau giá trị nhỏ hơn giá trị hiện tại. {2 5 3 4 7 5} -> {2 5 7}. Hoặc ví dụ để xóa tất cả các bản sao {3 5 4 2 3 5 6} -> {3 5 4 2 6}.

public class Filter {
    public static <T> void List(List<T> list, Chooser<T> chooser) {
        List<Integer> toBeRemoved = new ArrayList<>();
        leftloop:
        for (int right = 1; right < list.size(); ++right) {
            for (int left = 0; left < right; ++left) {
                if (toBeRemoved.contains(left)) {
                    continue;
                }
                Keep keep = chooser.choose(list.get(left), list.get(right));
                switch (keep) {
                    case LEFT:
                        toBeRemoved.add(right);
                        continue leftloop;
                    case RIGHT:
                        toBeRemoved.add(left);
                        break;
                    case NONE:
                        toBeRemoved.add(left);
                        toBeRemoved.add(right);
                        continue leftloop;
                }
            }
        }

        Collections.sort(toBeRemoved, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });

        for (int i : toBeRemoved) {
            if (i >= 0 && i < list.size()) {
                list.remove(i);
            }
        }
    }

    public static <T> void List(List<T> list, Keeper<T> keeper) {
        Iterator<T> iterator = list.iterator();
        while (iterator.hasNext()) {
            if (!keeper.keep(iterator.next())) {
                iterator.remove();
            }
        }
    }

    public interface Keeper<E> {
        boolean keep(E obj);
    }

    public interface Chooser<E> {
        Keep choose(E left, E right);
    }

    public enum Keep {
        LEFT, RIGHT, BOTH, NONE;
    }
}

Con ong này sẽ dùng như thế này.

List<String> names = new ArrayList<>();
names.add("Anders");
names.add("Stefan");
names.add("Anders");
Filter.List(names, new Filter.Chooser<String>() {
    @Override
    public Filter.Keep choose(String left, String right) {
        return left.equals(right) ? Filter.Keep.LEFT : Filter.Keep.BOTH;
    }
});

0

Với ổi:

Collection<Integer> collection = Lists.newArrayList(1, 2, 3, 4, 5);

Iterators.removeIf(collection.iterator(), new Predicate<Integer>() {
    @Override
    public boolean apply(Integer i) {
        return i % 2 == 0;
    }
});

System.out.println(collection); // Prints 1, 3, 5

0

Trong Java 8, Bạn có thể trực tiếp sử dụng phương thức lọc này và sau đó thực hiện điều đó.

 List<String> lines = Arrays.asList("java", "pramod", "example");

 List<String> result = lines.stream()              
         .filter(line -> !"pramod".equals(line))     
         .collect(Collectors.toList());              

 result.forEach(System.out::println); 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.