2009-04-10 34 views
21

Tôi có một vài câu hỏi thực sự.Phương pháp Java: Tìm đối tượng trong danh sách mảng cho biết giá trị thuộc tính đã biết

Tôi có một lớp Chó với instance fields sau:

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

Tôi cũng có một lớp Lưu Trữ mà có thể nhanh chóng Chó và đưa Dog đối tượng vào một ArrayList.

Tôi đang cố viết phương thức trong Lưu trữ lấy số nguyên làm ID và xem qua ArrayList và trả về đối tượng chứa ID đó.

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 

Có hai vấn đề với phương pháp này (các phương pháp khác tôi sử dụng công việc). Trước hết nó không hoạt động, và tôi không thể hiểu tại sao. Tôi đang trong khi lặp qua (có khả năng) tất cả các đối tượng trong arraylist, sau đó sau khi vòng lặp kết thúc, kiểm tra xem vòng lặp kết thúc vì nó đã hết các đối tượng để tìm kiếm, hoặc vì nó tìm thấy một đối tượng với ID đã cho . Thứ hai, điều đó có vẻ giống như một quá trình tốn nhiều thời gian. Có cách nào để tăng tốc độ này không?

+0

làm thế nào getSize() và al xác định? – cobbal

Trả lời

16

A while áp dụng cho cụm từ hoặc khối sau while.

Bạn không có một khối, vì vậy khi bạn kết thúc với sự biểu hiện dog=al.get(i);

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

Mọi thứ sau đó xảy ra một lần duy nhất.

Không có lý do gì để tạo một chú chó mới, vì bạn không bao giờ sử dụng chú chó bạn mới làm quen; bạn ngay lập tức chỉ định một Dog từ mảng để tham khảo con chó của bạn.

Và nếu bạn cần lấy giá trị cho khóa, bạn nên sử dụng Bản đồ chứ không phải một mảng.

Chỉnh sửa: đây không phải là lý do tại sao ??

Cảm nhận từ OP:

Một câu hỏi nữa liên quan đến việc không có để tạo ra một thể hiện mới của một con chó. Nếu tôi chỉ lấy ra các bản sao của các đối tượng từ danh sách mảng, làm thế nào tôi có thể lấy nó ra khỏi danh sách mảng mà không có một đối tượng mà tôi đặt nó? Tôi cũng nhận thấy rằng tôi đã không đánh dấu vòng lặp while.

Tham chiếu Java và đối tượng mà nó đề cập là những thứ khác nhau. Chúng giống như một đối tượng và tham chiếu C++, mặc dù một tham chiếu Java có thể được tái chỉ định như một con trỏ C++.

Kết quả là Dog dog; hoặc Dog dog = null cung cấp cho bạn tham chiếu trỏ đến không có đối tượng nào. new Dog()tạo một đối tượng có thể được trỏ đến.

Sau đó với dog = al.get(i) có nghĩa là tham chiếu hiện trỏ đến tham chiếu con chó được trả lại bởi al.get(i). Hiểu được, trong Java, các đối tượng không bao giờ được trả về, chỉ các tham chiếu đến các đối tượng (là các địa chỉ của đối tượng trong bộ nhớ).

Con trỏ/tham chiếu/địa chỉ của Chó bạn mới tạo hiện bị mất, vì không có mã nào đề cập đến nó, vì tham chiếu đã được thay thế bằng tham chiếu bạn nhận được từ al.get(). Cuối cùng, bộ thu gom rác Java sẽ phá hủy đối tượng đó; trong C++ bạn đã "rò rỉ" bộ nhớ.

Kết quả là bạn cần phải tạo biến có thể tham chiếu đến Chó; bạn không cần phải tạo Chó với new.

(Sự thật bạn không cần phải tạo tham chiếu, vì những gì bạn thực sự phải làm là trả lại những gì mà Map trả về từ hàm get() của nó. Nếu Map không được parametrized trên Dog, như thế này : Map<Dog>, khi đó bạn sẽ cần phải trả lại tiền, nhưng bạn sẽ không cần tham chiếu: return (Dog) map.get(id); hoặc nếu Bản đồ được tham số hóa, return map.get(id). Và một dòng đó là toàn bộ chức năng của bạn và nó sẽ nhanh hơn lặp lại một mảng cho hầu hết các trường hợp.)

+0

Tôi không nghĩ đây là câu trả lời mà anh ấy đang tìm kiếm. Bạn đang đúng về vòng lặp không làm những gì nó cần, nhưng đó không phải là điểm. Và tôi thực sự không hiểu ý của bạn về việc "làm mới" (tôi cho rằng bạn có nghĩa là tạo ra một ví dụ mới), mà anh ta thậm chí không muốn hoặc cần phải làm. – Jorn

+0

+1 để được tư vấn về Bản đồ. –

+0

Về ý kiến ​​của Jorn .. Tôi muốn nói đây là câu trả lời mà anh ta đang tìm kiếm. Tác giả nói rằng nó không hoạt động, tpdi giải thích tại sao nó không hoạt động. Nhận xét của bạn về việc tạo ra cá thể chó mới thật khó hiểu. tpdi giải thích rằng điều đó không cần thiết giống như bạn đang nói –

13

Bạn phải lặp qua toàn bộ mảng, không có thay đổi điều đó. Bạn có thể tuy nhiên, làm điều đó dễ dàng hơn một chút

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

hay không mới cho vòng lặp

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

Bạn không cần phải lặp qua danh sách. – Jon

+0

Quyền của Jon, nhưng +1 dù sao để đưa ra giải pháp tốt nhất/sạch nhất vẫn sử dụng danh sách (chứ không phải bản đồ). –

+0

Bạn vẫn phải lặp qua danh sách để tạo bản đồ ngay từ đầu. Có hay không hiệu quả hơn phụ thuộc vào nhiều yếu tố, bao gồm tần suất danh sách thay đổi và tần suất bạn cần tra cứu. – Jorn

16

Để cải thiện hiệu suất của trình hoạt động, nếu bạn đang luôn luôn muốn tìm kiếm đối tượng của một số số nhận dạng duy nhất, sau đó bạn có thể xem xét sử dụng Map<Integer,Dog>. Điều này sẽ cung cấp tra cứu liên tục theo thời gian. Bạn vẫn có thể lặp lại chính các đối tượng bằng cách sử dụng bản đồ values().

Một đoạn mã nhanh chóng để giúp bạn bắt đầu:

// 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); 

Điều này sẽ giúp điều tốc độ lên một chút nếu bạn đang thực hiện nhiều tra cứu về bản chất tương tự trong danh sách. Nếu bạn chỉ đang làm một tra cứu, sau đó bạn sẽ phải chịu cùng một chi phí vòng lặp bất kể.

1

Tôi đã quan tâm để thấy rằng áp phích gốc đã sử dụng một phong cách tránh lối ra sớm. Single Entry; Single Exit (SESE) là một phong cách thú vị mà tôi chưa thực sự khám phá. Đã muộn rồi và tôi đã có một chai rượu táo, vì vậy tôi đã viết một giải pháp (không được kiểm tra) mà không có lối ra sớm.

Tôi đã sử dụng trình lặp. Thật không may java.util.Iterator có tác dụng phụ trong phương thức nhận. (Tôi không thích những thiết kế Iterator do hậu quả của nó là ngoại lệ.)

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; 
} 

Lưu ý sự trùng lặp của biểu thức i!=dogs.length() (có thể chọn dogs.get(i).getID()!=id).

43

Giả sử bạn đã viết phương thức equals cho Dog đúng cách so sánh dựa trên id của Dog cách dễ nhất và đơn giản nhất để trả về một mục trong danh sách như sau.

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

Đó là hiệu suất ít hơn mà các cách tiếp cận khác ở đây. Bạn không cần một vòng lặp nào cả trong trường hợp này. Hi vọng điêu nay co ich.

P.S Bạn có thể sử dụng Apache Commons Lang để viết một đơn giản bằng phương pháp cho chó như sau:

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

Nếu bạn có để có được một thuộc tính đó không phải là ID. Tôi sẽ sử dụng 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()); 
} 
}); 
0

tôi giải quyết này bằng java 8 lambdas

int dogId = 2; 

return dogList.stream().filter(dog-> dogId == dog.getId()).collect(Collectors.toList()).get(0); 
Các vấn đề liên quan