Java-структура данных для имитации дерева данных - PullRequest
3 голосов
/ 18 ноября 2010

Мне нужна помощь в определении того, какой подход использовать.У меня есть SOAP-ответ, дающий мне файл XML.Мне нужно в конечном итоге с 3 коррелированных списков, отображаемых на экране.Когда вы выбираете один элемент в первом списке, соответствующие варианты появляются во втором списке и т. Д. Меня интересует только то, как эффективно организовать данные после их извлечения из потока XML.Вот фрагмент XML:

<device>
    <manufacturer>Acer</manufacturer>
    <model>A1</model>
    <platform>Android</platform>
</device>
<device>
    <manufacturer>Acer</manufacturer>
    <model>A1</model>
    <platform>J2ME</platform>
</device>
<device>
    <manufacturer>Acer</manufacturer>
    <model>A2</model>
    <platform>Android</platform>
</device>
<device>
    <manufacturer>Samsung</manufacturer>
    <model>E400</model>
    <platform>Android</platform>
</device>

Итак, у меня будет что-то вроде factory = {"Acer", "Acer", "Acer", "Samsung"}, model = {"A1", "A1"," A2 "," E400 "}, platform = {" Android "," J2ME "," Android "," Android "}.

Здесь начинается самое интересное: мне нужно обработать данные так,что я могу использовать его для отображения 3 списков.После выбора Android Acer и Samsung становятся доступными.Если выбран Acer, то доступны модели A1 и A2.Все списки должны быть отсортированы.В настоящее время я использую Sax для разбора данных на вектор объектов, содержащий поля производителя, модели, платформы.Все, о чем я могу думать, - это структура типа TreeMap.Мы ценим любые предложения.

Ответы [ 3 ]

4 голосов
/ 18 ноября 2010

Я не думаю, что иерархическая структура - это то, что вам нужно здесь.Потому что пользователь может выбрать первую платформу или производителя.Если он выбирает первый Android, вы хотите показать 3 устройства.Если он выберет первый Acer, он увидит 2 устройства.

Итак, я предлагаю следующее.

  1. создать класс Device со свойствами производителя, модели, платформы.
  2. создать простой связанный список, содержащий все эти устройства.
  3. Создать 2 карты: manufaturerIndex и plarformIndex, которые выглядят так:
    Map<String, Collection<Device>> manufacturerIndex;

  4. Итерируйте один раз по списку и заполните все карты индексов.

Например:

for(Device d : devices) {
    Collection<Device> selected = manufacturerIndex.get(d.getManufacturer());
    if (selected == null) {
         selected = new ArrayList<Device>();
         manufactuerIndex.put(d.getManufacturer(), selected);
    }
    selected.add(d);
    // the same for the second index
}

Теперь вы можете использовать структуру данных.

manufactuerIndex.get("Nokia") -> возвращает все устройства Nokia.

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

2 голосов
/ 18 ноября 2010

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

Вот мой объект Product:

public class Product implements Comparable<Product>{

    private final String manufacturer;
    private final String model;
    private final String platform;

    public Product(final String manufacturer,
        final String model,
        final String platform){
        this.manufacturer = manufacturer;
        this.model = model;
        this.platform = platform;
    }

    public String getManufacturer(){
        return manufacturer;
    }

    public String getModel(){
        return model;
    }

    public String getPlatform(){
        return platform;
    }

    @Override
    public int hashCode(){
        return Objects.hashCode(manufacturer, model, platform);
    }

    @Override
    public boolean equals(final Object obj){
        if(obj instanceof Product){
            final Product other = (Product) obj;
            return Objects.equal(manufacturer, other.manufacturer)
                && Objects.equal(model, other.model)
                && Objects.equal(platform, other.platform);
        }
        return false;
    }

    @Override
    public int compareTo(final Product o){
        return ComparisonChain
            .start()
            .compare(manufacturer, o.manufacturer)
            .compare(model, o.model)
            .compare(platform, o.platform)
            .result();
    }

}

Теперь я бы просто использовал TreeSet<Product> и применил к нему представления.Вот пример метода, который возвращает динамическое представление, отфильтрованное по модели:

public static Collection<Product> filterByModel(
    final Collection<Product> products,
    final String model){
    return Collections2.filter(products, new Predicate<Product>(){

        @Override
        public boolean apply(final Product product){
            return product.getModel().equals(model);
        }
    });
}

Используйте его следующим образом:

Collection<Product> products = new TreeSet<Product>();
// add some products
Collection<Product> filtered = filterByModel(products, "A1");

Обновление: Мы можем взять егоболее того, используя только одну коллекцию, подкрепленную связанными предикатами, которые, в свою очередь, связаны с моделью, поддерживаемой вашим представлением.Мозг болит?Проверьте это:

// this is the collection you sent to your view
final Collection<Product> visibleProducts =
    Collections2.filter(products, Predicates.and(Arrays.asList(
        new ManufacturerPredicate(yourViewModel),
        new ModelPredicate(yourViewModel),
        new PlatformModel(yourViewModel)))
);

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

Например, ModelPredicate проверяет все продукты в коллекции, чтобы определить, входит ли их модель в число выбранных.Поскольку здесь используется логика and, вы можете сделать ее иерархической структурой (если предикат производителя возвращает false, предикаты модели и платформы никогда не вызываются).

1 голос
/ 18 ноября 2010

Я использую вложенные карты для чего-то подобного.Используйте TreeMap, чтобы получить отсортированные результаты:

TreeMap<String, TreeMap<String, Model> manufacturerMap;

TreeMap<String, Model> models = manufacturerMap.get( name );
if( models == null ) {
    models = new TreeMap<String, Model>();
    manufacturerMap.put( name. models );
}

... etc ...
...