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

Не совсем уверен, как сформулировать этот вопрос. Мне интересно, есть ли способ проверить определенные части пользовательского класса 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, который позволяет быстро искать массив. скорость этого очень важна.

Ответ 1

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

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

например. Использование Коллекций Google:

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));

Ответ 2

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

При поиске значения эта внутренняя структура данных вернет индекс, используя двоичный поиск.

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

Что-то вроде следующего мнимого кода 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 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

К сожалению

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

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

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

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

 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"]

При поиске заданного атрибута вы берете соответствующий массив, например, если вы хотите найти имя "Reyes", вы получите массив "lastName"

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

И будет выполнять binarySearch на нем для "Reyes", который вернет элемент в позиции 2, который, в свою очередь, вернет index = 1, в котором находится позиция "Оскар" в исходном массиве.

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

Ответ 6

Посмотрите на класс 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

Ответ 7

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), например.