Поиск предикатов в Java - PullRequest
       38

Поиск предикатов в Java

11 голосов
/ 25 февраля 2010

Не совсем уверен, как сформулировать этот вопрос. Мне интересно, если есть метод, чтобы проверить определенные части пользовательского Java-класса, чтобы увидеть, соответствует ли он определенным критериям. Как это

public Name(String forename, String middlename, String surname)

А затем, когда создается массив экземпляров этого класса, говорят:

Name[] applicants = new Name[4];

applicants[0] = new Name("john","bob", "rush");
applicants[1] = new Name("joe","bob", "rushden");
applicants[2] = new Name("jack","bob", "rushden");
applicants[3] = new Name("jake","bob", "rushden");

Можно ли выполнить поиск по экземплярам класса для человека с

midddlename.equals("bob") && surname.equals("rush")

Я на самом деле не ищу решение, которое if(surname.equals("bob")) then else и т. Д.

Но это встроенный Java-класс, который позволяет осуществлять быстрый поиск по массиву. скорость этого очень важна.

Ответы [ 7 ]

14 голосов
/ 25 февраля 2010

Встроенная поддержка отсутствует, но Коллекции Apache и Коллекции Google предоставляют поддержку предикатов для коллекций.

Вы можете найти этот вопрос и ответы на него полезными. То же самое с этой developer.com статьей.

например. Использование Google Collections:

final Predicate<name> bobRushPredicate = new Predicate<name>() {
   public boolean apply(name n) {
      return "bob".equals(n.getMiddlename()) && "rush".equal(n.getSurname());
   }
}

final List<name> results = Iterables.filter(applicants, bobRushPredicate));
1 голос
/ 25 февраля 2010

Поиск по массиву и «скорость очень важна» на самом деле не идут вместе. Если ваш массив не будет очень маленьким, поиск в массиве никогда не будет быстрым. Это эквивалент полного сканирования таблицы в базе данных, производительность независимо от того, как вы это делаете, будет плохой. Ключом к быстрому поиску вещей является использование индексированной структуры. Вы все еще можете иметь массив, если он вам абсолютно необходим, но поиск должен выполняться с использованием другой структуры данных. Посмотрите коллекцию на основе Hash или Tree, поскольку они упорядочивают данные таким образом, чтобы их можно было очень быстро получить. TreeSet, TreeMap, HashSet, HashMap и т. Д. Хэширует индексные данные по хешированному ключу, деревья похожи, но также хранят свои данные в отсортированном порядке.

0 голосов
/ 19 апреля 2017

В Java 8 добавлены лямбда-выражения и потоковый API, поэтому поддержка теперь встроена.

Name[] applicants = new Name[4];

applicants[0] = new Name("john", "bob", "rush");
applicants[1] = new Name("joe", "bob", "rushden");
applicants[2] = new Name("jack", "bob", "rushden");
applicants[3] = new Name("jake", "bob", "rushden");

Optional<Name> result = Arrays.stream(applicants)
    .filter(name -> name.middlename.equals("bob") && name.surname.equals("rush"))
    .findAny();

result.ifPresent(name -> System.out.println(name));

Здесь доступно множество вариантов. Вы можете получить первое имя для сопоставления, переключив .findAny() на .findFirst() или запустить поиск параллельно, вставив .parallel() после .stream(applicants), например.

0 голосов
/ 27 февраля 2010

Посмотрите на класс ParallelArray, он удовлетворяет вашим требованиям, но вам нужно немного изучить концепции функционального программирования, чтобы эффективно его использовать.

Класс не поставляется с JDK 6, но может прийти с JDK 7 (обсуждается). Тем временем вы можете использовать его как библиотеку - скачайте пакет JSR166y из: http://gee.cs.oswego.edu/dl/concurrency-interest/

См. Этот учебник для подробного объяснения: http://www.ibm.com/developerworks/java/library/j-jtp03048.html

Это может показаться сложным, и это так (если вы просто копаетесь в высокопроизводительных многопоточных алгоритмах). Существует проект Groovy, который пытается обернуть более удобный API вокруг Parallel Array, так что вы можете посмотреть на него: http://gpars.codehaus.org/, http://gpars.codehaus.org/Parallelizer

0 голосов
/ 27 февраля 2010

Более быстрый способ, который я могу придумать, - это создать структуру данных, которая отражает значения свойств этого объекта и содержит внутренний индекс для каждого значения.

При поиске значения эта внутренняя структура данных возвращает индекс с использованием бинарного поиска.

Единственное требование - ваш объект должен зарегистрироваться и обновить эту структуру.

Что-то вроде следующего воображаемого UML / Python-подобного кода:

 // Holds the index number of a given value
 // for instance, name="Oscar" may be at index 42...
 IndexValuePair
     index : Int
     value : String 

     +_ new( value: String, index: Int ) 
          return IndexValuePair( value, index )

 ValuePairComparator --> Comparator 

     + compareTo( a: IndexValuePair, b: IndexValuePair ) : Int 

         return a.value.compareTo( b.value )

 SearchStructure
     - data = Object[] // The original array which contains your applicants
      // a list of arrays each one containing the property value, and the index on "data" where that value appears 
     - dataIndexes =  List(IndexValuePair)[String] // Map<List<IndexValuePair>> 
     - dataIndexexInitialized = false

     // Add an object to this structure
     + addObject( o: Object ) 
          if( ! dataIndexesInitialized, 
              initIndexesWith( o )
          )

          index = data.add( o ) // returns the index at which "o" was inserted
          addToIndexes( o, index ) 

     // Register all the properties values of the given object 
     // along with the index where they appear in the original array 
     - addToIndexes( object: Object, index: Int ) 
           forEach( property in Object , 
              list = dataIndexes[property]
              list.add( IndexValuePair.new( property.value, index ) ) 
           )
     // Create empty array for each property .. 
     - initIndexesWith( object : Object ) 
          forEach( property in object , 
                comparator = ValuePairComparator()
                list = List<IndexValuePair>()
                list.setComparator(  ) 
                dataIndexes[property] =  list
          )
          dataIndexesInitialized = true 


     // Search an object using the given criteria ( a Map<String, String> = key=value ) 
     + search( criteria: String[String] ) : List<Object>

        result = Set<Object>()

        // let's say criteria has:
        // ["name":"Oscar", "lastName"="Reyes"]
       forEach( key in criteria, 
            list = dataIndexes[key]  // "name", "lastname" ..etc. 
            valuePair = list.binarySearch( criteria[key] ) // first Oscar, later Reyes 
            result.add( data[valuePair.index] )
       ) 

       return result

Oops

Надеюсь, это понятно.

Дело в том, что если вы действительно хотите, чтобы это было действительно быстро, вы должны хранить индексы по свойству

  1. Массив для данных
  2. Массив для каждого свойства, который в свою очередь будет иметь индекс данных

Например, если у вас есть следующий массив:

 a = [ Object(name="Mike", lastName="Z" )
       Object(name="Oscar", lastName="Reyes" ) , 
       Object(name="Rahul", lastName="G" ) , 
       Object(name="Pie", lastName="154" )  ]

Они будут иметь позиции:

0 = Mike ... 
1 = Oscar ...
2 = Rahul ...
3 = Pie ...

И у вас будет два (в данном случае) отдельных массива, которые после сортировки будут:

nameArray =  ["Mike=0", "Oscar=1", "Pie=3", "Rahul=2"]

и

lastNameArray =   ["154=3", "G=2", "Reyes=1", "Z=0"]

Когда вы ищете определенный атрибут, вы берете соответствующий массив, например, если вы хотите найти фамилию «Рейес», вы получите массив «lastName»

 ["154=3", "G=2", "Reyes=1", "Z=0"]

И выполнит на нем двоичный поиск для «Рейес», который вернет элемент в позиции 2, который, в свою очередь, вернет индекс = 1, который является позицией «Оскар» в исходном массиве.

Это должно держать вещи под O (log n)

0 голосов
/ 25 февраля 2010

Используйте базу данных в памяти, такую ​​как Apache Derby или hsqldb . Воспользуйтесь JDBC, JPA или Hibernate, которые могут делать все, что вы хотите.

Профилируйте свой код. Тогда оптимизируй.

0 голосов
/ 25 февраля 2010

Если вам нужно выполнить поиск на основе проверки равенства объектов по массиву apache common ArrayUtils, вам, в основном, нужно переопределить свои равенства и hascode для имени объекта и использовать его, но если вы хотите использовать пользовательские критерии поиска, я думаю, у вас есть реализовать свой собственный путь, и нет встроенной поддержки языка Java

...