2013-08-27 46 views
6

Tôi đã tạo một ví dụ ngắn về vấn đề của mình. Tôi đang tạo danh sách các đối tượng nặc danh và thêm chúng vào ArrayList. Khi các mục có trong số ArrayList, sau đó tôi quay trở lại và thêm thông tin khác vào từng đối tượng trong danh sách. Có cách nào để trích xuất một đối tượng cụ thể từ danh sách nếu bạn không biết chỉ mục của nó?Nhận các đối tượng cụ thể từ ArrayList khi các đối tượng được thêm vào ẩn danh?

Tôi chỉ biết 'Tên' của đối tượng nhưng bạn không thể làm list.get(ObjectName) hoặc bất kỳ thứ gì. Cách được đề nghị để xử lý điều này là gì? Tôi không muốn phải lặp qua toàn bộ danh sách mỗi khi tôi muốn lấy một đối tượng cụ thể.

public class TestCode{ 

    public static void main (String args []) { 
     Cave cave = new Cave(); 

     // Loop adds several Parties to the cave's party list 
     cave.parties.add(new Party("FirstParty")); // all anonymously added 
     cave.parties.add(new Party("SecondParty")); 
     cave.parties.add(new Party("ThirdParty")); 

     // How do I go about setting the 'index' value of SecondParty for example? 
    } 
} 

class Cave { 
    ArrayList<Party> parties = new ArrayList<Party>(); 
} 

class Party extends CaveElement{ 
    int index; 

    public Party(String n){ 
     name = n; 
    } 

    // getter and setter methods 

    public String toString() { 
     return name; 
    } 
} 


class CaveElement { 
    String name = ""; 
    int index = 0; 

    public String toString() { 
     return name + "" + index; 
    } 
} 
+0

Bạn có phải sử dụng danh sách không? – smk

Trả lời

11

Với việc sử dụng các List, không có cách nào để "tra cứu" một giá trị mà không lặp lại qua nó ...

Ví dụ ...

Cave cave = new Cave(); 

// Loop adds several Parties to the cave's party list 
cave.parties.add(new Party("FirstParty")); // all anonymously added 
cave.parties.add(new Party("SecondParty")); 
cave.parties.add(new Party("ThirdParty")); 

for (Party p : cave.parties) { 
    if (p.name.equals("SecondParty") { 
     p.index = ...; 
     break; 
    } 
} 

Bây giờ, điều này sẽ mất thời gian. Nếu phần tử bạn đang tìm kiếm nằm ở cuối danh sách, bạn sẽ phải lặp lại đến cuối danh sách trước khi bạn tìm thấy một kết quả phù hợp.

Nó có thể là tốt hơn để sử dụng một Map của một số loại ...

Vì vậy, nếu chúng tôi cập nhật Cave để trông giống như ...

class Cave { 
    Map<String, Party> parties = new HashMap<String, Party>(25); 
} 

Chúng ta có thể làm điều gì đó giống như ...

Cave cave = new Cave(); 

// Loop adds several Parties to the cave's party list 
cave.parties.put("FirstParty", new Party("FirstParty")); // all anonymously added 
cave.parties.put("SecondParty", new Party("SecondParty")); 
cave.parties.put("ThirdParty", new Party("ThirdParty")); 

if (cave.parties.containsKey("SecondParty")) { 
    cave.parties.get("SecondParty").index = ... 
} 

Thay vào đó ...

Cuối cùng, điều này sẽ tất cả phụ thuộc vào những gì bạn muốn đạt được ...

+1

Tôi tin rằng đây là câu trả lời hữu ích nhất. Tôi sẽ không thể sử dụng Bản đồ, có nhiều hơn một chút đối với câu đố này hơn là tôi đưa vào câu hỏi này cho – leigero

+1

@leigero nếu bạn muốn tốt nhất của cả hai thế giới, bạn có thể sử dụng một 'HashMap' để lưu trữ ánh xạ' tên' -> chỉ mục .. –

+0

Thậm chí nếu bạn cần chức năng của Danh sách vì các lý do khác, bạn STILL tốt hơn khi chạy điều này dưới dạng 'LinkedHashMap' đằng sau hậu trường và chuyển nó thành Danh sách khi cần. Bản đồ hiệu quả hơn nhiều – StormeHawke

4

List.indexOf() sẽ cung cấp cho bạn những gì bạn muốn, miễn là bạn biết chính xác những gì bạn đang sau, và với điều kiện là phương pháp equals() cho Party là rõ ràng.

Party searchCandidate = new Party("FirstParty"); 
int index = cave.parties.indexOf(searchCandidate); 

Đây là nơi nó được thú vị - lớp con không nên kiểm tra tài sản riêng của cha mẹ, vì vậy chúng tôi sẽ xác định equals() trong lớp cha.

@Override 
public boolean equals(Object o) { 
    if (this == o) { 
     return true; 
    } 
    if (!(o instanceof CaveElement)) { 
     return false; 
    } 

    CaveElement that = (CaveElement) o; 

    if (index != that.index) { 
     return false; 
    } 
    if (name != null ? !name.equals(that.name) : that.name != null) { 
     return false; 
    } 

    return true; 
} 

Nó cũng khôn ngoan để ghi đè hashCode nếu bạn ghi đè equals - hợp đồng chung của hashCode nhiệm vụ đó, nếu x.equals(y), sau đó x.hashCode() == y.hashCode().

@Override 
public int hashCode() { 
    int result = name != null ? name.hashCode() : 0; 
    result = 31 * result + index; 
    return result; 
} 
+0

Vâng bạn đã đúng, xấu của tôi. Là một ngày dài: P –

5

Nếu bạn muốn để tra cứu các đối tượng dựa trên tên String của họ, đây là một trường hợp sách giáo khoa cho một Map, nói một HashMap. Bạn có thể sử dụng LinkedHashMap và chuyển đổi nó thành List hoặc Array sau này (Chris đã đề cập đến điều này một cách độc đáo trong các nhận xét bên dưới).

LinkedHashMap vì nó cho phép bạn truy cập các phần tử theo thứ tự bạn chèn chúng nếu bạn muốn. Nếu không, HashMap hoặc TreeMap sẽ thực hiện.

Bạn có thể làm điều này để làm việc với List như những người khác đang đề xuất, nhưng điều đó cảm thấy Hacky với tôi .. và điều này sẽ sạch hơn cả trong ngắn hạn và dài hạn.

Nếu bạn PHẢI sử dụng danh sách cho đối tượng, bạn vẫn có thể lưu Map tên đối tượng vào chỉ mục trong mảng. Đây là một chút xấu xí hơn, nhưng bạn nhận được hiệu suất gần như giống như một đồng bằng Map.

+2

Cụ thể, bạn luôn có thể sử dụng 'map.values ​​(). ToArray (new Party [0])' để kết xuất vào một mảng và bạn có thể sử dụng 'new ArrayList (map.values ​​()) 'để đưa vào danh sách. –

+1

Trong tất cả câu trả lời 5 hoặc 6 cho đến giờ, tôi thích câu trả lời của bạn nhất. Nó có O (1) tra cứu và vẫn duy trì thứ tự chèn. –

+0

@ ChrisJester-Young yup cảm ơn, đó là lý do tại sao tôi đề nghị 'LinkedHashMap', tôi nên làm rõ rằng –

0

Tôi khuyên bạn nên ghi đè số equals(Object) trong lớp Party của mình. Nó có thể giống như thế này:

public boolean equals(Object o){ 
    if(o == null) 
     return false; 
    if(o instanceof String) 
     return name.equalsIgnoreCase((String)o); 
    else if(o instanceof Party) 
     return equals(((Party)o).name); 
    return false; 
} 

Sau khi bạn làm điều đó, bạn có thể sử dụng phương pháp indexOf(Object) để lấy chỉ số của các bên theo quy định của tên của nó, như hình dưới đây:

int index = cave.parties.indexOf("SecondParty"); 

Would return chỉ số của Party với tên SecondParty.

Lưu ý: Tính năng này chỉ hoạt động vì bạn đang ghi đè phương pháp equals(Object).

+0

Tôi cũng đề nghị rằng nó vi phạm hợp đồng 'equals', nhưng đó chỉ là MHO: P – MadProgrammer

+0

@MadProgrammer Eh, có vẻ khá tiện lợi: P –

+1

Thuận tiện, nhưng điều gì sẽ xảy ra nếu bạn có hai đối tượng' Bên' giống nhau, nhưng có chỉ mục khác nhau. Hợp đồng bây giờ đã bị hỏng;) – MadProgrammer

2

Bạn có thể sử dụng lỗi list.indexOf(Object) trong tất cả sự trung thực những gì bạn mô tả âm thanh như bạn muốn sử dụng hiệu quả hơn khi sử dụng số Map.

Hãy thử điều này:

Map<String, Object> mapOfObjects = new HashMap<String, Object>(); 
mapOfObjects.put("objectName", object); 

Sau đó, sau khi bạn muốn lấy lại đối tượng, sử dụng

mapOfObjects.get("objectName"); 

Giả sử bạn không biết tên của đối tượng như bạn đã nêu, đây sẽ là cả bụi và sẽ có hiệu suất nhanh hơn bên cạnh, đặc biệt nếu bản đồ chứa số lượng lớn các đối tượng.

Nếu bạn cần các đối tượng trong Map ở lại trật tự, bạn có thể sử dụng

Map<String, Object> mapOfObjects = new LinkedHashMap<String, Object>(); 

thay

1

Theo yêu cầu câu hỏi của bạn, tôi muốn đề xuất rằng Bản đồ sẽ giải quyết vấn đề của bạn rất hiệu quả và không gặp bất kỳ rắc rối nào.

Trong bản đồ, bạn có thể đặt tên làm khóa và đối tượng gốc làm giá trị.

Map<String,Cave> myMap=new HashMap<String,Cave>(); 
0

Bạn có thể chỉ cần tạo phương thức để lấy đối tượng theo tên của nó.

public Party getPartyByName(String name) { 
    for(Party party : parties) { 
     if(name.equalsIgnoreCase(party.name)) { 
      return party; 
     } 
    } 
    return null; 
} 
Các vấn đề liên quan