programing

컬렉션 내에서 지정된 속성을 가진 모든 개체 찾기

nasanasas 2020. 9. 15. 07:54
반응형

컬렉션 내에서 지정된 속성을 가진 모든 개체 찾기 [중복]


이 질문에 이미 답변이 있습니다.

나이, 좋아하는 고양이 먹이 등과 같은 많은 속성을 가진 고양이와 같은 복잡한 개체가 있습니다.

한 무리의 고양이가 Java 컬렉션에 저장되어 있으며, 3 살이 된 모든 고양이 또는 가장 좋아하는 고양이 먹이가 Whiskas 인 고양이를 찾아야합니다. 확실히 특정 속성을 가진 Cats를 찾는 사용자 지정 메서드를 작성할 수 있지만 속성이 많으면 번거 롭습니다. 이 작업을 수행하는 일반적인 방법이 있습니까?


메서드를 정의하는 인터페이스의 인스턴스를 사용하는 check(Cat)메서드를 작성할 수 있습니다. 여기서 해당 메서드는 원하는 속성 검사로 구현할 수 있습니다.

더 나은 방법은 일반화하는 것입니다.

public interface Checker<T> {
    public boolean check(T obj);
}

public class CatChecker implements Checker<Cat> {
    public boolean check(Cat cat) {
        return (cat.age == 3); // or whatever, implement your comparison here
    }
}

// put this in some class
public static <T> Collection<T> findAll(Collection<T> coll, Checker<T> chk) {
    LinkedList<T> l = new LinkedList<T>();
    for (T obj : coll) {
         if (chk.check(obj))
             l.add(obj);
    }
    return l;
}

물론, 다른 사람들이 말하는 것처럼 이것은 관계형 데이터베이스가 만들어진 이유입니다.


Commons Collections API를 사용해보십시오.

List<Cat> bigList = ....; // master list

Collection<Cat> smallList = CollectionUtils.select(bigList, new Predicate() {
    public boolean evaluate(Object o) {
        Cat c = (Cat)o;
        return c.getFavoriteFood().equals("Wiskas") 
            && c.getWhateverElse().equals(Something);
    }
});

물론 매번 익명 클래스를 사용할 필요는 없으며 Predicate일반적으로 사용되는 검색을위한 인터페이스 구현을 만들 수 있습니다 .


저는 이런 종류의 문제에 대해 Google Collections (현재 Guava 라고 함 )를 사용하고 있습니다. 정말 유용한 메서드의 매개 변수로 Predicate라는 인터페이스를 사용할 수있는 Iterables라는 클래스가 있습니다.

Cat theOne = Iterables.find(cats, new Predicate<Cat>() {
    public boolean apply(Cat arg) { return arg.age() == 3; }
});

여기에서 확인 하세요 !


Java 8 람다 표현식을 사용하면 다음과 같은 작업을 수행 할 수 있습니다.

cats.stream()
    .filter( c -> c.getAge() == 3 && c.getFavoriteFood() == WHISKAS )
    .collect(Collectors.toList());

개념적으로 Guava Predicate 접근 방식과 동일하지만 람다를 사용하면 훨씬 깔끔해 보입니다.

아마도 OP에 대한 유효한 대답은 아니지만 비슷한 필요를 가진 사람들에게 주목할 가치가 있습니다. :)


Jxpath를 사용하는 것이 좋습니다 . xpath가 같은 곳 에서처럼 객체 그래프에 대한 쿼리를 수행 할 수 있습니다.

JXPathContext.newContext(cats).
     getValue("//*[@drinks='milk']")

다시 commons collections API를 사용하여 : Predicate를 별도로 구현하면 "checker"유형 코드를 얻게됩니다.

public class CatPredicate implements Predicate {

    private int age; 


    public CatPredicate(int age) {
        super();
        this.age = age;
    }


    @Override
    public boolean evaluate(Object o) {
        Cat c (Cat)o;
        return c.getAge()==this.age;
    }

}

다음과 같이 사용됩니다.

CollectionUtils.filter(catCollectionToFilter, new CatPredicate(3))

lambdaj 를 사용할 수 있습니다 . 다음과 같은 것은 사소하고 구문은 매우 부드럽습니다.

Person me = new Person("Mario", "Fusco", 35);
Person luca = new Person("Luca", "Marrocco", 29);
Person biagio = new Person("Biagio", "Beatrice", 39);
Person celestino = new Person("Celestino", "Bellone", 29);
List<Person> meAndMyFriends = asList(me, luca, biagio, celestino);
List<Person> oldFriends = filter(having(on(Person.class).getAge(), greaterThan(30)), meAndMyFriends);

훨씬 더 복잡한 일을 할 수 있습니다. Matchers를 위해 햄 크레스트사용합니다 . 어떤 사람들은 이것이 자바 스타일이 아니라고 주장 할 것입니다.하지만이 사람이 자바를 비틀어 약간의 기능적 프로그래밍을 만드는 것은 재미 있습니다. 소스 코드도 살펴보세요. 꽤 공상 과학입니다.


Commons 컬렉션 사용 :

EqualPredicate nameEqlPredicate = new EqualPredicate(3);
BeanPredicate beanPredicate = new BeanPredicate("age", nameEqlPredicate);
return CollectionUtils.filter(cats, beanPredicate);

참고로이 질문에 Guava를 사용하는 다른 답변이 3 개 있지만 질문에 대한 답변이 없습니다. 질문자는 속성이 일치하는 모든 고양이를 찾고 싶다고 말했습니다. 예를 들어 3 세는 Iterables.find존재하는 경우 하나만 일치합니다. Iterables.filterGuava 를 사용 하는 경우이를 달성 하려면을 사용해야 합니다. 예를 들면 다음과 같습니다.

Iterable<Cat> matches = Iterables.filter(cats, new Predicate<Cat>() {
    @Override
    public boolean apply(Cat input) {
        return input.getAge() == 3;
    }
});

.NET에서 LINQ를 사용하는 것과 매우 흡사합니다.

아직 Java에 대한 "실제"LINQ 구현은 없지만 설명을 쉽게 수행 할 수 있는 Quaere살펴볼 수 있습니다.


JoSQL과 같은 것을 사용하고 컬렉션에 대해 'SQL'을 작성할 수 있습니다. http://josql.sourceforge.net/

더 복잡한 쿼리를 수행 할 수 있다는 추가 이점과 함께 원하는대로 들립니다.


You could try some of the generic code in the Apache Commons project. The Collections subproject provides code for finding objects that match a particular Predicate, as well as a large number of predicates (equals, null, instanceof, etc). The BeanUtils subproject allows you to make predicates that test properties of beans.

Use the CollectionUtils class to search within a collection. There are a few methods for this, but check out the select() method, in particular. Use the following classes to construct predicates, or write your own: Predicate, PredicateUtils, BeanPredicate.

This is all sometimes a bit cumbersome, but at least it's generic! :-)


Solutions based on predicates, filters and custom iterators/comparators are nice, but they don't provide analogue with database index. For instance: I would like to search collection of cats different ways: by sex and age and by age, so it looks like two indexes: 1) [sex, age] 2) [age]. Values, accessed by that indexes could be hashed, to implement fast lookup, without iterating the whole collection. Is anywhere there such solution?


Use Google Guava.

final int lastSeq = myCollections.size();
Clazz target = Iterables.find(myCollections, new Predicate<Clazz>() {
    @Override
    public boolean apply(@Nullable Clazz input) {
      return input.getSeq() == lastSeq;
    }
});

I think to use this method.


You could store those objects on a database. If you don't want the overhead of a full blown database server you can use an embedded one like HSQLDB. Then you can use Hibernate or BeanKeeper (simpler to use) or other ORM to map objects to tables. You keep using the OO model and get the advanced storage and querying benefits from a database.


Here's an idea for a searcher class you could parameterize with the specific values you want to look for.

You could go further and store the names of the properties as well, probably in a Map with the desired values. In this case you would use reflection on the Cat class to call the appropriate methods given the property names.

public class CatSearcher {

  private Integer ageToFind = null;
  private String  foodToFind = null;

  public CatSearcher( Integer age, String food ) {
    this.ageToFind = age;
    this.foodToFind = food;
  }

  private boolean isMatch(Cat cat) {
    if ( this.ageToFind != null && !cat.getAge().equals(this.ageToFind) ) {
       return false;
    }
    if ( this.foodToFind != null && !cat.getFood().equals(this.foodToFind) {
       return false;
    }
    return true;
  }

  public Collection<Cat> search( Collection<Cat> listToSearch ) {
    // details left to the imagination, but basically iterate over
    // the input list, call isMatch on each element, and if true
    // add it to a local collection which is returned at the end.
  }

}

JFilter http://code.google.com/p/jfilter/ suites your requirement.

JFilter is a simple and high performance open source library to query collection of Java beans.

Key features

  • Support of collection (java.util.Collection, java.util.Map and Array) properties.
  • Support of collection inside collection of any depth.
  • Support of inner queries.
  • Support of parameterized queries.
  • Can filter 1 million records in few 100 ms.
  • Filter ( query) is given in simple json format, it is like Mangodb queries. Following are some examples.
    • { "id":{"$le":"10"}
      • where object id property is less than equals to 10.
    • { "id": {"$in":["0", "100"]}}
      • where object id property is 0 or 100.
    • {"lineItems":{"lineAmount":"1"}}
      • where lineItems collection property of parameterized type has lineAmount equals to 1.
    • { "$and":[{"id": "0"}, {"billingAddress":{"city":"DEL"}}]}
      • where id property is 0 and billingAddress.city property is DEL.
    • {"lineItems":{"taxes":{ "key":{"code":"GST"}, "value":{"$gt": "1.01"}}}}
      • where lineItems collection property of parameterized type which has taxes map type property of parameteriszed type has code equals to GST value greater than 1.01.
    • {'$or':[{'code':'10'},{'skus': {'$and':[{'price':{'$in':['20', '40']}}, {'code':'RedApple'}]}}]}
      • Select all products where product code is 10 or sku price in 20 and 40 and sku code is "RedApple".

Guava has a very powerful searching capabilities when it comes to such type of problems. For example, if your area searching an object based on one of it properties you may consider:

Iterables.tryFind(listOfCats, new Predicate<Cat>(){
    @Override
    boolean apply(@Nullable Cat input) {
        return "tom".equalsIgnoreCase(input.name());
    }
}).or(new Cat("Tom"));

in case it's possible that the Tom cat is not in the listOfCats, it will be returned, thus allowing you to avoid NPE.


A very common problem and I have used google collections and here is my code

public class FindByIdPredicate implements Predicate<IDObject> {

private Long entityId;

public FindByIdPredicate(final Long entityId) {
    this.entityId = entityId;

}

@Override
public boolean apply(final IDObject input) {
    return input.getId().equals(this.entityId);
}

/**
     * Pass in the Collection
 * @param Collection
 * @return IdObject if present or null
 */
public IDObject getEntity(final Collection<? extends IDObject> collection) {

    for (IDObject idObject : collection) {
        if (this.apply(idObject)) {
            return idObject;
        }
    }
    return null;

}

/**
 * @param Set
 * @return IdObject if present or null
 */
@SuppressWarnings("unchecked")
public <T> T getEntity(final Set<? extends IDObject> set) {

    for (IDObject idObject : set) {
        if (this.apply(idObject)) {
            return (T) idObject;
        }
    }
    return null;

}

}

Hope this helps


you can search item from a list as follows function. good luck!

int _searchList(List<T> list,T item) {
int idx = -1;
idx = Collections.binarySearch(list,item,
        new Comparator<T>() {
            public int compare(Titm1,
                    Titm2) {

                // key1
                if (itm1.key1.compareTo(itm2.key1) != 0) {
                    return itm1.key2.compareTo(itm2.key2);
                }

                // key2
                return itm1.key2
                        .compareTo(itm2.key2);
            }
        });

return idx;

}

참고URL : https://stackoverflow.com/questions/587404/finding-all-objects-that-have-a-given-property-inside-a-collection

반응형