2010-02-25 1 views
11

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

+5

Преждевременная оптимизация? –

+1

вам не следует использовать Массивы, если вам не нужно, списки - лучшее решение в 99.99999% всех случаев. –

+0

Почему это вопрос Java Object Question? – fastcodejava

ответ

14

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

Вы можете найти this question и его ответы будут полезны. То же самое с этой статьей 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)); 
+0

есть ли где-нибудь, чтобы получить учебники или больше примеров использования предикатов из google colletions? – pie154

+0

Java 8 добавлена ​​встроенная поддержка. Я добавил пример в качестве ответа. – Andrew

0

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

0

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

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

1

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

+0

Просто небольшое примечание, но структуры, о которых вы говорите, деревья и карты, все еще основаны на массивах. Они просто используют специальные методы для поиска массива. – Matt

+0

Есть способы поиска массива быстрее, сначала сортировка массива однажды ускорит поиск от линейного до логарифмического, во-вторых - это одна из проблем с «смущающей паранджелизуемостью» (см. Мой ответ выше). – ddimitrov

0

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

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

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

что-то вроде следующего мысленного 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 

Нам

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

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

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

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

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

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

Это должен держать все под O (журнал N)

0

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

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

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

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

0

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