Поиск атрибута внутри вектора на Java - PullRequest
2 голосов
/ 29 июня 2009

У меня есть Vector объектов, и я должен искать внутри случайный атрибут этих объектов (например, Plane класс, Vector, содержащий Plane; и я должен искать иногда для destination, а для других pilotName).

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


Обновление 1:

Код, который я написал, выглядит примерно так (Java n00b alert!):

public int search(String whatSearch, String query){  
    int place = -1;  
    boolean found = false;  
    for ( Iterator<Plane> iteraPlane = this.planes.iterator(); iteraPlane.hasNext() && found == false; ) {  
        Plane temp = (Plane) iteraPlane.next();  
        /* Here is where I have to search for one of many attributes (delimited by whatSearch */ 
    }  
return place;  
}

Кажется, я должен придерживаться линейного поиска (и это цена, которую я могу заплатить). Во всяком случае, я подумал, если бы в Java было что-то вроде имя переменной переменной (ой!)

Ответы [ 5 ]

4 голосов
/ 29 июня 2009

Я предполагаю, что ваша проблема в том, что вы хотите иметь метод, который ищет результат на основе некоторого свойства типа коллекции. Java слаб в этом, потому что это лучше всего выражено на языке, который имеет замыкания. Что вам нужно, это что-то вроде:

public interface Predicate<T> {
    public boolean evaluate(T t);
}

И тогда ваш метод поиска выглядит так:

public static <T> T findFirst(List<T> l, Predicate<T> p) { //use List, not Vector
    for (T t : l) { if (p.evaluate(t)) return t; }
    return null;
}

Тогда любой может использовать этот универсальный метод поиска. Например, для поиска числа в векторе Integer s:

List<Integer> is = ...
findFirst(is, new Predicate<Integer> {
    public boolean evaluate(Integer i) { return i % 2 == 0; }
});

Но вы можете реализовать предикат любым способом, каким захотите; для любого произвольного поиска

2 голосов
/ 29 июня 2009

Используйте Collections.binarySearch и предоставьте Comparator.

РЕДАКТИРОВАТЬ: Предполагается, что Vector отсортирован. В противном случае необходимо выполнить линейный поиск.

0 голосов
/ 30 июня 2009

См. @Oxbow_lakes выше - я думаю, что вам нужно не передавать String как whatSearch, это передать небольшой фрагмент кода, который знает, как получить интересующее вас свойство. менее общая версия:

public static interface PlaneMatcher {
    boolean matches(Plane plane, String query);
}


public int search(PlaneMatcher matcher, String query){  
    int place = -1;  
    boolean found = false;  
    for ( Iterator<Plane> iteraPlane = this.planes.iterator(); iteraPlane.hasNext() && found == false; ) {  
        Plane temp = (Plane) iteraPlane.next();  
        if (matcher.matches(temp, query) {
            found = true;
        }
        place++;
    }  
    return place;  
}

...
// example

int pilotNameIndex = search(new PlaneMatcher() {
        boolean matches(Plane plane, String query) {
            // note: assumes query non-null; you probably want to check that earlier
            return query.equals(plane.getPilotName());
        }
    }, "Orville Wright");

(Кстати, если вам интересен именно индекс, а не сам Plane, я бы не стал беспокоиться о Iterator - просто используйте старомодный цикл for (int i = 0; i < planes.size(); i++), и когда у вас есть совпадение, return i.)

Теперь, хитрый момент в том, что то, что вы должны искать, действительно идентифицируется произвольными строками во время выполнения. Если это так, я могу предложить две альтернативы:

  1. Не храните эти значения как поля объекта - plane.pilotName, plane.destination - вообще. Просто имейте Map<String, String> (или еще лучше Map<Field, String>, где Field - это Enum всех допустимых полей), называемое что-то вроде plane.metadata.
  2. Сохраните их как поля объектов, но предварительно заполните карту от имен полей до PlaneMatcher экземпляров, как описано выше.

Например:

private static final Map<String, PlaneMatcher> MATCHERS = Collections.unmodifiableMap(new HashMap<String, PlaneMatcher>() {{
    put("pilotName", new PlaneMatcher() {
        boolean matches(Plane plane, String query) {
            return query.equals(plane.getPilotName());
        });
    ...
    put("destination", new PlaneMatcher() {
        boolean matches(Plane plane, String query) {
            return query.equals(plane.getDestination());
        });
}}

...

public int search(String whatSearch, String query){  
    PlaneMatcher matcher = MATCHERS.get(whatSearch);
    int place = -1;  
    boolean found = false;  
    for ( Iterator<Plane> iteraPlane = this.planes.iterator(); iteraPlane.hasNext() && found == false; ) {  
        Plane temp = (Plane) iteraPlane.next();  
        if (matcher.matches(temp, query) {
            found = true;
        }
        place++;
    }  
    return place;  
}

О, и вы можете испытать желание использовать отражение. Не. :)

0 голосов
/ 29 июня 2009

метод equals() - лучший вариант. Для этих итераций вы можете сделать что-то вроде этого:

for (Plane plane: planes) {
   if ("JFK".equals(plane.getDestination())) {
      // do your work in here;
   }
}

или вы можете переопределить метод equals() в Plane, чтобы проверить, соответствует ли передаваемая строка вашей цели (или пилоту). это позволит вам использовать методы indexOf(Object) и indexOf(Object, index) для Vector, чтобы вернуть вам индекс (ы) объекта (ов). Получив это, вы можете использовать Vector.get(index), чтобы вернуться к объекту для вас.

в Plane.java:

public boolean equals(Object o) {
    return o.equals(getDestination()) ||
           o.equals(getPilot()) ||
           super.equals(o);    

}

с этой опцией еще предстоит проделать дополнительную работу, поскольку вам также потребуется переопределить hashCode() ( см. Документацию ).

0 голосов
/ 29 июня 2009

Простой способ - передать функцию сравнения в вашу процедуру поиска. Или, если вам нужно больше скорости, используйте дженерики.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...