Метод Java: поиск объекта в списке массивов по известному значению атрибута - PullRequest
21 голосов
/ 11 апреля 2009

У меня есть пара вопросов на самом деле.

У меня есть класс Dog со следующими полями экземпляра:

private int id;
private int id_mother;
private int id_father;
private String name="";
private String owner="";
private String bDate="";

У меня также есть класс Архив , который может создавать экземпляры Dog и помещать объекты Dog в ArrayList.

Я пытаюсь написать метод в Archive , который принимает целое число в качестве идентификатора и просматривает ArrayList и возвращает объект, содержащий этот идентификатор.

private Dog getDog(int id){
    Dog dog = new Dog();
    int length=getSize();
    int i=0;

    dog=al.get(i);
    i++;

    while(dog.getId()!=id && i<length)
        dog=al.get(i);
        i++;

    if(dog.getId()!=id)
        dog=null;
    return dog;
}//end getDog

Есть две проблемы с этим методом (другие методы, которые я использую, работают). Прежде всего, это не работает, и я не понимаю, почему. Я пока зацикливаю (потенциально) все объекты в массиве, потому что после завершения цикла я проверяю, завершился ли цикл, потому что у него закончились объекты для поиска, или потому что он нашел объект с данным идентификатором , Во-вторых, это кажется очень трудоемким процессом. Есть ли способ ускорить это?

Ответы [ 8 ]

44 голосов
/ 11 апреля 2009

Предполагая, что вы правильно написали метод для Собаки, который сравнивает на основе идентификатора Собаки, самый простой и простой способ вернуть элемент в списке:

if (dogList.contains(dog)) {
   return dogList.get(dogList.indexOf(dog));
}

Это менее интенсивно, чем другие подходы здесь. Вам не нужен цикл вообще в этом случае. Надеюсь, это поможет.

P.S. Вы можете использовать Apache Commons Lang, чтобы написать простой метод равных для Dog следующим образом:

@Override
public boolean equals(Object obj) {     
   EqualsBuilder builder = new EqualsBuilder().append(this.getId(), obj.getId());               
   return builder.isEquals();
}
16 голосов
/ 11 апреля 2009

Чтобы повысить производительность операции, если вы всегда хотите искать объекты по какому-то уникальному идентификатору, вы можете рассмотреть возможность использования Map<Integer,Dog>. Это обеспечит постоянный поиск по ключу. Вы все еще можете перебирать сами объекты, используя карту values().

Быстрый фрагмент кода для начала работы:

// Populate the map
Map<Integer,Dog> dogs = new HashMap<Integer,Dog>();
for( Dog dog : /* dog source */ ) {
    dogs.put( dog.getId(), dog );
}

// Perform a lookup
Dog dog = dogs.get( id );

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

16 голосов
/ 11 апреля 2009

A while применяется к выражению или блоку после while.

У вас нет блока, поэтому ваше время заканчивается выражением dog=al.get(i);

while(dog.getId()!=id && i<length)
                dog=al.get(i);

Все после этого происходит только один раз.

Нет никаких оснований для создания собаки, так как вы никогда не используете собаку, которую вы новичок; вы немедленно присваиваете Dog из массива для ссылки на вашу собаку.

И если вам нужно получить значение для ключа, вы должны использовать карту, а не массив.

Редактировать: почему это было не так ?? 1015 *

Комментарий от ОП:

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

Ссылка на Java и объект, на который она ссылается, это разные вещи. Они очень похожи на ссылку и объект C ++, хотя ссылку на Java можно перенаправить, как указатель C ++.

В результате Dog dog; или Dog dog = null дает вам ссылку, которая не указывает ни на один объект. new Dog() создает объект, на который можно указать.

После этого с dog = al.get(i) означает, что ссылка теперь указывает на ссылку собаки, возвращаемую al.get(i). Поймите, в Java объекты никогда не возвращаются, только ссылки на объекты (которые являются адресами объекта в памяти).

Указатель / ссылка / адрес собаки, которую вы обновили, теперь утерян, так как ни один код не ссылается на нее, поскольку референт был заменен референтом, который вы получили от al.get(). В конце концов Java-сборщик мусора уничтожит этот объект; в C ++ вы бы «вытекли» из памяти.

В результате вам нужно создать переменную, которая может ссылаться на Dog; вам не нужно создавать собаку с new.

(На самом деле вам не нужно создавать ссылку, поскольку то, что вы действительно должны делать, это возвращать то, что Map возвращает из своей функции get (). Если Map не параметризована для Dog, например, так: Map<Dog>, тогда вам нужно будет привести результат из get, но вам не понадобится ссылка: return (Dog) map.get(id); или, если карта параметризована, return map.get(id). И эта одна строка - вся ваша функция, и она в большинстве случаев это будет быстрее, чем итерация массива.)

13 голосов
/ 11 апреля 2009

Вы должны пройти через весь массив, это не нужно менять. Однако вы можете сделать это немного проще

for (Dog dog : list) {
  if (dog.getId() == id) {
    return dog; //gotcha!
  }
}
return null; // dog not found.

или без нового цикла for

for (int i = 0; i < list.size(); i++) {
  if (list.get(i).getId() == id) {
    return list.get(i);
  }
}
1 голос
/ 11 апреля 2009

Мне было интересно видеть, что оригинальный плакат использовал стиль, который избегал ранних выходов. Однократная; Single Exit (SESE) - интересный стиль, который я на самом деле не исследовал. Уже поздно, и у меня есть бутылка сидра, поэтому я написал решение (не тестировалось) без досрочного выхода.

Я должен был использовать итератор. К сожалению, java.util.Iterator имеет побочный эффект в методе get. (Мне не нравится дизайн Iterator из-за его исключительных последствий.)

private Dog findDog(int id) {
    int i = 0;
    for (; i!=dogs.length() && dogs.get(i).getID()!=id; ++i) {
        ;
    }

    return i!=dogs.length() ? dogs.get(i) : null;
}

Обратите внимание на дублирование выражения i!=dogs.length() (возможно, выбрал dogs.get(i).getID()!=id).

0 голосов
/ 10 июня 2019
List<YourClass> list = ArrayList<YourClass>();


List<String> userNames = list.stream().map(m -> m.getUserName()).collect(Collectors.toList());

Выход: [ "Джон", "Алекс"]

0 голосов
/ 23 августа 2017

Я решил это с помощью Java 8 лямбда

int dogId = 2;

return dogList.stream().filter(dog-> dogId == dog.getId()).collect(Collectors.toList()).get(0);
0 голосов
/ 06 мая 2013

Если вам нужно получить атрибут, который не является идентификатором. Я бы использовал CollectionUtils .

Dog someDog = new Dog();
Dog dog = CollectionUtils(dogList, new Predicate() {

@Override
public boolean evaluate(Object o)
{
    Dog d = (Dog)o;
    return someDog.getName().equals(d.getName());
}
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...