Java, поиск в списке объектов? - PullRequest
15 голосов
/ 04 марта 2011

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

Я нашел, как выполнять обычный поиск по списку, но мне нужно, например, найти значение результата выполнения вызова getName () для каждого объекта в списке и получить объекты, которые имеют результат, соответствующий моему вход.

Что-то вроде ниже, где третий аргумент является результатом вызова метода, а второй - то, что я пытаюсь найти.

   int index = Collections.binarySearch(myList, "value", getName());

Любой совет приветствуется

Ответы [ 6 ]

10 голосов
/ 04 марта 2011

Если вам, как разовой операции, нужно найти объект (ы), для которого getName () является определенным значением, то, вероятно, не так уж много волшебства: прокрутить список, вызвать getName () для каждого объекта,и для тех, которые совпадают, добавьте их в свой список результатов.

Если getName () - дорогостоящая операция, и есть какой-то другой способ априорной разработки, если данный объект определенно не будет возвращать совпадающеезначение, то, очевидно, вы можете встроить эту «фильтрацию» при циклическом просмотре.

Если вам часто нужно извлекать объекты для заданного getName (), сохраните индекс (например, в HashMap) для [resultgetName () -> object -> список совпадений].Вам нужно решить, как и если вам нужно синхронизировать этот «индекс» с фактическим списком.

См. Также другое предложение по использованию binarySearch (), но для сохранения списка в рабочем состоянии.Таким образом, вставки обходятся дороже, чем с картой и несортированным списком, но если вставки встречаются нечасто по сравнению с поиском, то преимущество заключается в необходимости поддерживать только одну структуру.

10 голосов
/ 04 марта 2011

Взгляните на бинарный поиск, который использует компаратор :

public static int binarySearch (Список списка, Т ключ, Компаратор с)

Итак, вы бы сделали что-то вроде:

class FooComparator
    implements Comparator<Foo>
{
    public int compare(T a, T b)
    {
        return (a.getName().compareTo(b.getName());
    }
}

int index = Collections.binarySearch(myList, "value", new FooComparator());

Сначала вам нужно будет отсортировать список курса (Collections.sort также принимает Comaprator ...).

9 голосов
/ 04 марта 2011

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

1.- Создайте метод поиска, который выполняет итерацию коллекции, и передайте объект, который сообщает вамесли ваш объект должен быть возвращен или нет.

2.- Запустите этот метод и создайте анонимный внутренний класс с критериями

3.- Получите новый список в отдельной переменной.

Примерно так:

result = search( aList, new Matcher(){ public boolean matches( Some some ) { 
  if( some.name().equals("a")) { 
     return true;
  }
}});

Вот рабочая демонстрация:

import java.util.*;
class LinearSearchDemo { 
  public static void main( String ... args ) { 
      List<Person> list = Arrays.asList(
                                  Person.create("Oscar", 0x20),
                                  Person.create("Reyes", 0x30),
                                  Person.create("Java", 0x10)
                          );

      List<Person> result = searchIn( list, 
              new Matcher<Person>() { 
                  public boolean matches( Person p ) { 
                      return p.getName().equals("Java");
              }});

      System.out.println( result );

      result = searchIn( list, 
              new Matcher<Person>() { 
                  public boolean matches( Person p ) { 
                      return p.getAge() > 16;
              }});

      System.out.println( result );

  }
  public static <T> List<T> searchIn( List<T> list , Matcher<T> m ) { 
      List<T> r = new ArrayList<T>();
      for( T t : list ) { 
          if( m.matches( t ) ) { 
              r.add( t );
          }
      }
      return r;
  }
}

class Person { 
  String name;
  int age;

  String getName(){ 
      return name;
  }
  int getAge() { 
      return age;
  }
  static Person create( String name, int age ) { 
      Person p = new Person();
      p.name = name;
      p.age = age;
      return p;
  }
  public String toString() { 
      return String.format("Person(%s,%s)", name, age );
  }    
}
interface Matcher<T> { 
  public boolean matches( T t );
}

Вывод:

[Person(Java,16)]
[Person(Oscar,32), Person(Reyes,48)]
2 голосов
/ 14 ноября 2012

Чтобы сделать это более масштабируемым образом, без простой итерации / фильтрации объектов, посмотрите ответ на аналогичный вопрос: Как вы запрашиваете коллекции объектов в Java (Criteria / SQL-like)?

1 голос
/ 04 марта 2011

Если объекты неизменны (или вы, по крайней мере, знаете, что их имена не изменятся), вы можете создать индекс с помощью HashMap.

Вам нужно будет заполнить карту и поддерживать ее в актуальном состоянии.

Map map = new HashMap();

map.put(myObject.getName(), myObject);
... repeat for each object ...

Затем вы можете использовать map.get("Some name"); для поиска по вашему индексу.

0 голосов
/ 04 марта 2011

Одна библиотека, с которой я знаком, - это Guava - вы можете создать ее Predicate , чтобы извлечь элементы из Iterable.Нет необходимости предварительно сортировать коллекцию.(Это, в свою очередь, означает, что это O (N), но это удобно.)

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