답변:
Java 8 ( 2014 )은 한 줄의 코드로 스트림과 람다를 사용하여이 문제를 해결합니다.
List<Person> beerDrinkers = persons.stream()
.filter(p -> p.getAge() > 16).collect(Collectors.toList());
튜토리얼은 다음과 같습니다 .
Collection#removeIf
컬렉션을 제자리에 수정하는 데 사용 합니다. (주의 사항 :이 경우 술어는 술어를 만족시키는 오브젝트를 제거합니다) :
persons.removeIf(p -> p.getAge() <= 16);
lambdaj를 사용하면 루프 나 내부 클래스를 작성하지 않고도 컬렉션을 필터링 할 수 있습니다.
List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
greaterThan(16)));
더 읽기 쉬운 것을 상상할 수 있습니까?
면책 조항 : 나는 lambdaj에 기고자입니다
persons.removeIf(p -> p.getAge() <= 16);
Java 1.5 를 사용하고 있고 Google Collections를 추가 할 수 없다고 가정하면 Google 직원 과 매우 유사한 작업을 수행합니다. 이것은 Jon의 의견에 약간의 변형입니다.
먼저이 인터페이스를 코드베이스에 추가하십시오.
public interface IPredicate<T> { boolean apply(T type); }
구현자는 특정 술어가 특정 유형에 해당하면 응답 할 수 있습니다. 예 경우 T
했다 User
및 AuthorizedUserPredicate<User>
구현은 IPredicate<T>
다음 AuthorizedUserPredicate#apply
전달 여부를 반환 User
권한이 부여됩니다.
그런 다음 일부 유틸리티 클래스에서는
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;
}
따라서 위의 내용을 사용한다고 가정하면
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);
선형 검사의 성능이 중요하다면 대상 컬렉션이있는 도메인 개체를 원할 수 있습니다. 대상 컬렉션이있는 도메인 개체에는 대상 컬렉션을 초기화, 추가 및 설정하는 메서드에 대한 필터링 논리가 있습니다.
최신 정보:
유틸리티 클래스 (Predicate라고 함)에서 술어가 예상 값을 반환하지 않을 때 기본값 옵션과 함께 select 메소드를 추가했으며 새 IPredicate 내에서 매개 변수를 사용할 정적 속성도 추가했습니다.
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;
}
}
다음 예제는 컬렉션간에 누락 된 개체를 찾습니다.
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;
}
});
다음 예제는 컬렉션에서 인스턴스를 찾고 인스턴스를 찾을 수 없을 때 컬렉션의 첫 번째 요소를 기본값으로 반환합니다.
MyType myObject = Predicate.select(collectionOfMyType, new IPredicate<MyType>() {
public boolean apply(MyType objectOfMyType) {
return objectOfMyType.isDefault();
}}, collectionOfMyType.get(0));
업데이트 (Java 8 릴리스 이후) :
I (Alan)이이 답변을 처음 게시 한 지 몇 년이 지났지 만 여전히이 답변에 대한 SO 포인트를 수집하고 있다고 믿을 수 없습니다. 어쨌든 Java 8이 언어에 대한 클로저를 도입 했으므로 이제는 대답이 상당히 달라지고 더 간단 해졌습니다. Java 8에서는 고유 한 정적 유틸리티 클래스가 필요하지 않습니다. 따라서 술어와 일치하는 첫 번째 요소를 찾으려면.
final UserService userService = ... // perhaps injected IoC
final Optional<UserModel> userOption = userCollection.stream().filter(u -> {
boolean isAuthorized = userService.isAuthorized(u);
return isAuthorized;
}).findFirst();
선택적 항목에 대한 JDK 8 API는 능력이있다 get()
, isPresent()
, orElse(defaultUser)
, orElseGet(userSupplier)
및 orElseThrow(exceptionSupplier)
뿐만 아니라 같은 다른 '모나드'기능 map
, flatMap
및 filter
.
술어와 일치하는 모든 사용자를 단순히 수집하려면를 사용 Collectors
하여 원하는 콜렉션에서 스트림을 종료하십시오.
final UserService userService = ... // perhaps injected IoC
final List<UserModel> userOption = userCollection.stream().filter(u -> {
boolean isAuthorized = userService.isAuthorized(u);
return isAuthorized;
}).collect(Collectors.toList());
val authorized = for (user <- users if user.isAuthorized) yield user
Apache Commons의 CollectionUtils.filter (Collection, Predicate)를 사용하십시오 .
"최상의"방법은 요청이 너무 넓습니다. "가장 짧습니까?" "가장 빠르다"? "읽기 쉬운"? 제자리에서 또는 다른 컬렉션으로 필터링 하시겠습니까?
가장 단순하지만 읽기 쉬운 방법은 반복하고 Iterator.remove () 메서드를 사용하는 것입니다.
Iterator<Foo> it = col.iterator();
while( it.hasNext() ) {
Foo foo = it.next();
if( !condition(foo) ) it.remove();
}
이제 더 읽기 쉽게하기 위해 유틸리티 메소드로 랩핑 할 수 있습니다. 그런 다음 IPredicate 인터페이스를 발명하고 해당 인터페이스의 익명 구현을 작성하고 다음과 같은 작업을 수행하십시오.
CollectionUtils.filterInPlace(col,
new IPredicate<Foo>(){
public boolean keepIt(Foo foo) {
return foo.isBar();
}
});
여기서 filterInPlace ()는 컬렉션을 반복하고 Predicate.keepIt ()을 호출하여 컬렉션에 유지할 인스턴스가 있는지 확인합니다.
나는이 작업을 위해 타사 라이브러리를 가져 오는 것에 대한 정당화를 실제로 보지 못합니다.
stream()
기능을하지만 모두가 최신 장난감을 재생 가져옵니다 P
제네릭을 지원하는 업데이트 된 컬렉션 프레임 워크에 대해서는 Google 컬렉션 을 고려하십시오 .
업데이트 : Google 컬렉션 라이브러리는 더 이상 사용되지 않습니다. 대신 최신 버전의 구아바 를 사용해야합니다 . 술어를 기반으로 필터링하는 메커니즘을 포함하여 콜렉션 프레임 워크에 대한 모든 확장이 여전히 있습니다.
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());
personList.removeIf(p -> p.age < 30);
있습니다. 덜 장황합니다. 또한 s가 매우 유용하고 빠르지 만 s로 가거나 나가는 속도가 느리기 때문에 s Stream
대신 s 를 수락하고 반환하는 api를 구현하기 시작한다는 이야기를 들었습니다 . Collection
Stream
Java 8의 초기 릴리스 이후 다음과 같은 것을 시도해 볼 수 있습니다.
Collection<T> collection = ...;
Stream<T> stream = collection.stream().filter(...);
예를 들어, 정수 목록이 있고> 10보다 큰 숫자를 필터링 한 다음 해당 숫자를 콘솔에 인쇄하려면 다음과 같이 할 수 있습니다.
List<Integer> numbers = Arrays.asList(12, 74, 5, 8, 16);
numbers.stream().filter(n -> n > 10).forEach(System.out::println);
내가 던질거야 RxJava을 에도 사용할 수있는 링에 안드로이드 . RxJava가 항상 최상의 옵션은 아니지만 콜렉션에 더 많은 변환을 추가하거나 필터링하는 동안 오류를 처리하려는 경우 유연성이 향상됩니다.
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);
}
});
산출:
1
3
5
RxJava의에 대한 자세한 세부 사항은 filter
찾을 수 있습니다 여기에 .
설정:
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();
}
}
}
사용법 :
List<MyObject> myList = ...;
filterCollection(myList, new Predicate<MyObject>() {
public boolean filter(MyObject obj) {
return obj.shouldFilter();
}
});
평범하고 단호한 자바는 어떻습니까?
List<Customer> list ...;
List<Customer> newList = new ArrayList<>();
for (Customer c : list){
if (c.getName().equals("dd")) newList.add(c);
}
간단하고 읽기 쉽고 (Android에서 작동합니다!) 그러나 Java 8을 사용하는 경우 달콤한 한 줄로 할 수 있습니다.
List<Customer> newList = list.stream().filter(c -> c.getName().equals("dd")).collect(toList());
toList ()를 정적으로 가져옵니다.
반복자가 아닌 콜렉션 자체를 필터링 하시겠습니까?
org.apache.commons.collections.iterators.FilterIterator를 참조하십시오.
또는 아파치 커먼즈 org.apache.commons.collections4.iterators.FilterIterator 버전 4 사용
Eclipse Collections를 사용하여 내장 JDK 목록 및 MutableList 를 필터링하는 방법을 살펴 보겠습니다 .
List<Integer> jdkList = Arrays.asList(1, 2, 3, 4, 5);
MutableList<Integer> ecList = Lists.mutable.with(1, 2, 3, 4, 5);
3보다 작은 숫자를 필터링하려면 다음과 같은 출력이 필요합니다.
List<Integer> selected = Lists.mutable.with(1, 2);
List<Integer> rejected = Lists.mutable.with(3, 4, 5);
다음은 Java 8 람다를 사용하여 필터링하는 방법 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));
익명 내부 클래스를로 사용하여 필터링하는 방법은 다음과 같습니다 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));
다음은 Predicates 팩토리를 사용하여 JDK 목록 및 Eclipse 콜렉션 MutableList 를 필터링하는 몇 가지 대안 입니다.
Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));
Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));
다음은 Predicates2 팩토리를 대신 사용하는 selectWith
메소드를 사용하여 술어에 오브젝트를 할당하지 않는 버전입니다 Predicate2
.
Assert.assertEquals(
selected, ecList.selectWith(Predicates2.<Integer>lessThan(), 3));
때때로 부정적인 조건을 필터링하려고합니다. Eclipse Collections에는 특별한 메소드가 reject
있습니다.
Assert.assertEquals(rejected, Iterate.reject(jdkList, lessThan3));
Assert.assertEquals(rejected, ecList.reject(lessThan3));
이 메소드 partition
는에 의해 선택되고 거부 된 요소를 포함하는 두 개의 콜렉션을 리턴합니다 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());
참고 : 저는 Eclipse Collections의 커미터입니다.
removeIf
프리미티브에 대해 목록을 작성하거나 설정 하는 방법은 무엇입니까?
ForEach DSL을 사용하면
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();
[The, quick, brown, fox, jumps, over, the lazy, dog] 모음이 주어지면 [quick, brown, jumps, over, lazy], 즉 3 문자보다 긴 모든 문자열이됩니다.
ForEach DSL에서 지원하는 모든 반복 스타일은 다음과 같습니다.
AllSatisfy
AnySatisfy
Collect
Counnt
CutPieces
Detect
GroupedBy
IndexOf
InjectInto
Reject
Select
자세한 내용은 https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEach 를 참조 하십시오.
Google 구아바 라이브러리 의 Collections2.filter (Collection, Predicate) 메소드 는 원하는 것을 수행합니다.
Java 9 Collectors.filtering
가 사용 가능 하므로 :
public static <T, A, R>
Collector<T, ?, R> filtering(Predicate<? super T> predicate,
Collector<? super T, A, R> downstream)
따라서 필터링은 다음과 같아야합니다.
collection.stream().collect(Collectors.filtering(predicate, collector))
예:
List<Integer> oddNumbers = List.of(1, 19, 15, 10, -10).stream()
.collect(Collectors.filtering(i -> i % 2 == 1, Collectors.toList()));
이것은 실제 클로저가 부족한 것과 함께 Java의 가장 큰 그립입니다. 솔직히, 위에서 언급 한 대부분의 방법은 읽기 쉽고 정말 효율적입니다. 그러나 .Net, Erlang 등으로 시간을 보낸 후 언어 수준에서 통합 된 목록 이해력은 모든 것을 훨씬 깨끗하게 만듭니다. 언어 수준에서 추가하지 않으면 Java는이 영역의 다른 많은 언어만큼 깨끗할 수 없습니다.
성능이 큰 관심사 인 경우 Google 컬렉션을 사용하는 것이 좋습니다 (또는 간단한 술어 유틸리티 작성). Lambdaj 구문은 일부 사람들에게 더 읽기 쉽지만 효율적이지 않습니다.
그리고 내가 쓴 라이브러리가 있습니다. 나는 그것의 효율성 (그렇습니다, 그 나쁜 것)에 관한 질문을 무시할 것입니다 ... 그렇습니다, 나는 그것의 명백한 반성을 기반으로 알고 있으며, 실제로 그것을 사용하지는 않지만 작동합니다 :
LinkedList<Person> list = ......
LinkedList<Person> filtered =
Query.from(list).where(Condition.ensure("age", Op.GTE, 21));
또는
LinkedList<Person> list = ....
LinkedList<Person> filtered = Query.from(list).where("x => x.age >= 21");
JFilter http://code.google.com/p/jfilter/ 는 요구 사항에 가장 적합합니다.
JFilter는 Java Bean의 콜렉션을 조회하기위한 단순하고 고성능의 오픈 소스 라이브러리입니다.
주요 특징들
컬렉션 내용을 복사하지 않고 기능 알고리즘 적용을 지원 하는 확장 된 Iterable 클래스 를 작성 했습니다.
용법:
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);
}
위의 코드는 실제로 실행됩니다
for( int n : myList )
{
if( n % 2 == 0 )
{
System.out.println(n);
}
}
CQEngine (컬렉션 쿼리 엔진)을 사용하십시오 . 이 작업을 수행하는 가장 빠른 방법입니다.
여기에 정말 좋은 답변이 있습니다. 나는 가능한 한 단순하고 읽기 쉬운 씬을 유지하고 싶습니다.
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();
}
}
}
}
}
https://code.google.com/p/joquery/
다양한 가능성을 지원합니다.
주어진 컬렉션,
Collection<Dto> testList = new ArrayList<>();
유형의
class Dto
{
private int id;
private String text;
public int getId()
{
return id;
}
public int getText()
{
return text;
}
}
필터
자바 7
Filter<Dto> query = CQ.<Dto>filter(testList)
.where()
.property("id").eq().value(1);
Collection<Dto> filtered = query.list();
자바 8
Filter<Dto> query = CQ.<Dto>filter(testList)
.where()
.property(Dto::getId)
.eq().value(1);
Collection<Dto> filtered = query.list();
또한,
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"});
정렬 (Java 7에도 사용 가능)
Filter<Dto> query = CQ.<Dto>filter(testList)
.orderBy()
.property(Dto::getId)
.property(Dto::getName)
Collection<Dto> sorted = query.list();
그룹화 (Java 7에도 사용 가능)
GroupQuery<Integer,Dto> query = CQ.<Dto,Dto>query(testList)
.group()
.groupBy(Dto::getId)
Collection<Grouping<Integer,Dto>> grouped = query.list();
조인 (Java 7에서도 사용 가능)
주어진,
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<>();
다음과 같이 참여할 수 있습니다.
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();
표현
Filter<Dto> query = CQ.<Dto>filter()
.from(testList)
.where()
.exec(s -> s.getId() + 1).eq().value(2);
내 대답은 Kevin Wong의 봄CollectionUtils
부터 Java 8 람다 식을 사용하는 단일 라이너로 작성 합니다.
CollectionUtils.filter(list, p -> ((Person) p).getAge() > 16);
이것은 내가 본 다른 대안처럼 간결하고 읽을 수 있습니다 (화면 기반 라이브러리를 사용하지 않고)
Spring CollectionUtils 는 스프링 버전 4.0.2.RELEASE에서 사용 가능하며 JDK 1.8 및 언어 레벨 8 이상이 필요합니다.
목록에 이미 존재하는 값에 따라 목록을 필터링해야했습니다. 예를 들어, 현재 값보다 작은 다음 값을 모두 제거하십시오. {2 5 3 4 7 5}-> {2 5 7}. 또는 예를 들어 모든 중복을 제거하려면 {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;
}
}
이 같은 꿀벌이 사용됩니다.
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;
}
});