2013-08-27 4 views
6

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

Я знаю только имя объекта, но вы не можете сделать list.get(ObjectName) или что-то еще. Каков рекомендуемый способ справиться с этим? Я бы предпочел не перебирать весь список каждый раз, когда я хочу получить один конкретный объект.

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

Нужно ли использовать список? – smk

ответ

11

Учитывая использование List, нет никакого способа «поиск» значения без перебора это ...

Например ...

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

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

Это может быть лучше использовать Map какой-то ...

Таким образом, если мы обновляем Cave, чтобы выглядеть ...

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

Мы могли бы сделать что-то вроде ...

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 = ... 
} 

Вместо ...

В конечном счете, это будет все зависит от того, чего вы хотите достичь ...

+1

Я считаю, что это самый полезный ответ. Я не смогу использовать карту, есть еще немного для этой головоломки, чем я включил для этих вопросов для спасибо за ответ. Спасибо за ответ. – leigero

+1

@leigero, если вы хотите получить лучшее из обоих миров, вы можете использовать 'HashMap' для хранения отображения' name' -> index .. –

+0

Даже если вам нужно функциональность List по другим причинам, вы STILL лучше выполняете это как «LinkedHashMap» за кулисами и конвертируете его в список по мере необходимости. Карты намного эффективнее – StormeHawke

4

List.indexOf() даст вам то, что вы хотите, если вы знаете точно, что вы после этого, и при условии, что метод equals() для Party хорошо определены.

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

Это становится интересно - подклассы не следует изучение частных свойств своих родителей, поэтому мы определим equals() в суперкласса.

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

Это также целесообразно, чтобы переопределить hashCode, если переопределить equals - общий контракт на hashCode мандатами что, если x.equals(y), то x.hashCode() == y.hashCode().

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

Да, ты был прав, мой плохой. Был длинный день: P –

5

Если вы хотите выполнять поиск объектов на основе их String названия, это хрестоматийный пример для Map, скажет HashMap. Вы можете использовать LinkedHashMap и преобразовать его в List или Array позже (Крис хорошо это описал в комментариях ниже).

LinkedHashMap потому что он позволяет вам получить доступ к элементам в том порядке, в котором вы их вставляете, если вы хотите это сделать. В противном случае HashMap или TreeMap сделаю.

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

Если вы ДОЛЖНЫ использовать список для объекта, вы все равно можете сохранить Map имени объекта в индекс в массиве. Это немного уродливее, но вы получаете почти ту же производительность, что и обычный Map.

+2

В частности, вы всегда можете использовать 'map.values ​​(). ToArray (new Party [0])' для сброса в массив, и вы можете использовать 'new ArrayList (map.values ​​()) 'для сброса в список. –

+1

Из всех ответов 5 или 6 до сих пор мне нравится ваш лучший. Он имеет O (1) поиск и по-прежнему поддерживает порядок вставки. –

+0

@ ChrisJester-Young yup спасибо, вот почему я предлагаю 'LinkedHashMap', я должен сделать это явным –

0

Я бы предложил переопределить equals(Object) вашего класса Party. Это может выглядеть примерно так:

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

После вы сделаете это, вы могли бы использовать метод indexOf(Object) для получения индекса партии, указанной по имени, как показано ниже:

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

вернуться бы индекс Party с именем SecondParty.

Примечание: Это работает только потому, что вы переопределяете метод equals(Object).

+0

Я бы также предположил, что это нарушение контракта 'equals', но это только MHO: P – MadProgrammer

+0

@MadProgrammer Eh, кажется, очень удобен: P –

+1

Удобно, возможно, но что произойдет, если у вас есть два объекта' Party', названных то же, но там индексы разные. Контракт теперь нарушен;) – MadProgrammer

2

Вы можете использовать ошибку list.indexOf(Object), если честно, то, что вы описываете, звучит так, будто вам будет лучше с помощью Map.

Попробуйте это:

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

Тогда позже, когда вы хотите получить объект, используйте

mapOfObjects.get("objectName"); 

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

Если вам нужны объекты в Map, чтобы остаться в порядке, вы можете использовать

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

вместо

1

Согласно вашему требованию к вопросу, я хотел бы предложить, что Карта решит вашу проблему очень эффективно и без каких-либо проблем.

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

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

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

public Party getPartyByName(String name) { 
    for(Party party : parties) { 
     if(name.equalsIgnoreCase(party.name)) { 
      return party; 
     } 
    } 
    return null; 
} 
Смежные вопросы