Подтвердить что ты не робот

Метод Java: поиск объекта в списке массивов с учетом известного значения атрибута

На самом деле у меня есть несколько вопросов.

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

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

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

Я пытаюсь написать метод в Архив, который принимает целое число как идентификатор и просматривает 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

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

4b9b3361

Ответ 1

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

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

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

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

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

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

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

Комментарий от OP:

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

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

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

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

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

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

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

Ответ 2

Предполагая, что вы правильно написали метод equals для Dog, который сравнивается на основе идентификатора собаки, самый простой и простой способ вернуть элемент в списке выглядит следующим образом.

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

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

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

@Override
public boolean equals(Object obj) {     
   EqualsBuilder builder = new EqualsBuilder().append(this.getId(), obj.getId());               
   return builder.isEquals();
}

Ответ 3

Чтобы повысить производительность операции, если вы всегда захотите искать объекты по уникальному идентификатору, вы можете использовать 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 );

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

Ответ 4

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

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

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

for (int i = 0; i < list.size(); i++) {
  if (list.get(i).getId() == id) {
    return list.get(i);
  }
}

Ответ 5

Мне было интересно увидеть, что оригинальный плакат использовал стиль, который избегал ранних выходов. Однократная; 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).

Ответ 6

Если вам нужно получить атрибут, который не является идентификатором. Я бы использовал 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());
}
});

Ответ 7

Я решил это, используя java 8 lambdas

int dogId = 2;

return dogList.stream().filter(dog-> dogId == dog.getId()).collect(Collectors.toList()).get(0);

Ответ 8

List<YourClass> list = ArrayList<YourClass>();


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

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