Работаете со свойствами объектов в списке? - PullRequest
4 голосов
/ 09 мая 2011

С учетом следующего кода:

public class MyObject { 

String myProperty;

public MyObject(String propertyValue) {
    myProperty=propertyValue; 
}
}

и

public class Main {

public static void main(String[] args) {

    ArrayList<MyObject> objects = new ArrayList<MyObject>();
    objects.add(new MyObject("first"));
    objects.add(new MyObject("second"));
    objects.add(new MyObject("third"));

    // Now do Task A and Task B
}
}

Сейчас я ищу лучший способ сделать следующее:

Задача A: Найти все объекты, где myProperty равно "second". Есть ли что-то вроде

ArrayList<MyObject> filteredObjects = objects.findPropertyValue(myProperty, "second") ?

Задача B: извлечь различные значения myProperty из списка, что означает, что я хочу получить массив, который включает в себя («первый», «второй», «третий») Есть ли что-то вроде

ArrayList propertyValues = objects.getPropertyValues(myProperty) ?

Я знаю, что Задачи A и B могут быть решены с помощью цикла через ArrayList, но мне интересно, есть ли лучший способ / уже что-то встроенное в Eclipse? Спасибо за любую подсказку: -)

Обратите внимание, что я не хочу использовать внешние библиотеки (в настоящее время я занимаюсь разработкой для Android и хочу, чтобы мое приложение было небольшим).

Ответы [ 4 ]

1 голос
/ 09 мая 2011

Если вам нужен первый (Задача A), это может означать, что ArrayList не является оптимальной структурой данных, которую вы должны использовать. Этот тип доступа должен заставить вас рассмотреть возможность использования Map или MultiMap (реализовано в Apache Commons Collections ).

Но ... Если тебе действительно нужны такие вещи. Несколько библиотек пригодятся.

В последнее время популярна Гуава . Другой - LambdaJ , который кажется более специализированным:

// Task A
filter(having(on(MyObject.class).getPropertyValue(), equalTo("second")), objects);

// Task B
convert(objects, new PropertyExtractor("propertyValue"));
// or even
extract(objects, on(MyObject.class).getPropertyValue());

(у меня не было возможности скомпилировать / запустить код, который я набрал, поэтому, пожалуйста, не будьте слишком строги с этим)

0 голосов
/ 09 мая 2011

По общему признанию, следующее немного рекламирует мою работу, но оно точно соответствует вашей проблеме.

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

Я не знаю о других библиотеках, предложенных здесь, но если вы хотите взглянуть на http://tbull.org/projects/util4j/,, это небольшая библиотека, которую я написал сам, и лицензия позволяет ей брать то, что вам нужно исходный код и включите его в свой собственный источник.

В этом подходе используются специально созданные Grepper s и Mapper s, поэтому нет необходимости в отражении. Это действительно очень похоже на то, что уже написал Amitay Dobo, но эта библиотека предоставляет более универсальные режимы работы, включая чтение элементов ввода из Iterator s и ленивое сопоставление / отображение.

Задача A: Найти все объекты, где myProperty равно «second». Есть ли что-то вроде

ArrayList<MyObject> filteredObjects = objects.findPropertyValue(myProperty, "second") ?

Это будет сделано как

import org.tbull.util.Collections;
import org.tbull.util.Grepper;

private static class PropertyGrepper implements Grepper<MyObject> {
    public final String property;
    public PropertyGrepper(String property) {
        this.property = property;
    }
    public @Override boolean grep(MyObject element) {
        return element.myProperty.equals(property);
    }
}

List<MyObject> filteredObjects = Collections.grep(new PropertyGrepper("second"), objects);

Задача B: Извлечь различные значения myProperty из списка, что означает, что я хочу получить массив, который включает («первый», «второй», «третий»). Есть ли что-то вроде

ArrayList propertyValues = objects.getPropertyValues(myProperty) ?
import org.tbull.util.Collections;
import org.tbull.util.Mapper;

private static class PropertyExtractor implements Mapper<MyObject, String> {
    public @Override String map(MyObject element) {
        return element.myProperty;
    }
}

List<String> propertyValues = Collections.map(new PropertyExtractor(), objects);

Отказ от ответственности: этот код не проверен. myProperty должен быть доступен для этой работы, либо public, либо предоставленный функцией получения.

Конечно, вы можете использовать анонимные внутренние классы для краткости или публично реализовать Grepper / Mapper для повторного использования.

0 голосов
/ 09 мая 2011

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

Если добавить новую библиотеку в проект не вариант, выможете написать собственное общее решение.Тем не менее, я настоятельно рекомендую вам добавить некоторые общие библиотеки, такие как Guava или Apache Commons, как было предложено ранее.

Две задачи, которые вы пытаетесь выполнить, можно более широко описать как фильтрацию и сопоставление (или выборпроектирование).Фильтрация может быть обобщена с помощью предиката - простой функции, которая будет возвращать, должен ли объект быть включен в новую коллекцию.Сопоставление может быть достигнуто с помощью универсальной функции, которая берет один исходный объект (в вашем случае, MyObject) и возвращает объект другого типа (в вашем случае, String).

Эти операции над множествамипроще поддерживать языки, некоторые из которых скомпилированы в JVM, такие как python (jython), groovy и scala.Но я предполагаю, что нельзя использовать другой язык для проекта.

Поэтому я продемонстрирую, как этого можно добиться в Java, хотя синтаксис немного более грубый, так как мы будем использоватьанонимные классы для предиката и преобразователя.

Существует простой пример самодельной фильтрации в Каков наилучший способ фильтрации коллекции Java? , поэтому я буду использовать его впример.

Два необходимых нам интерфейса:

public interface Convertor<FROM, TO> {
         TO convert(FROM from);
    }

public interface Predicate<T> {
    boolean apply(T type);
}

И фактическая «библиотека»:

import java.util.ArrayList;
import java.util.Collection;


public class CollectionUtils {
    public static <FROM, TO> Collection<TO> select(Collection<FROM> from, Convertor<FROM, TO> convertor) {
        Collection<TO> result = new ArrayList<TO>();
        for (FROM fromItem: from) {
            result.add(convertor.convert(fromItem));
        }
        return result;
    }

    public static <T> Collection<T> filter(Collection<T> target, Predicate<T> predicate) {
        Collection<T> result = new ArrayList<T>();
        for (T element: target) {
            if (predicate.apply(element)) {
                result.add(element);
            }
        }
        return result;
    }

}

Теперь мы можем легко выполнить две задачи:

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;

public class Main {

    public static void main(String[] args) {

        ArrayList<MyObject> objects = new ArrayList<MyObject>();
        objects.add(new MyObject("first"));
        objects.add(new MyObject("second"));
        objects.add(new MyObject("third"));

        // Now do Task A and Task B

        // Task A: Filter
        Collection<MyObject> filtered = CollectionUtils.filter(objects, new Predicate<MyObject>() {

            @Override
            public boolean apply(MyObject myObject) {
                return myObject.myProperty.equals("second");
            }
        });
        for (MyObject myObject: filtered) {System.out.println(myObject.myProperty);}
        System.out.println();

        // TASK B: Map/Select
        Collection<String> transforemd = CollectionUtils.select(objects, new Convertor<MyObject, String>() {

            @Override
            public String convert(MyObject from) {
                return from.myProperty;
            }
        });

        for (String str: transforemd) {System.out.println(str);}
    }
}

Теперь было бы очень просто изменить предикат для фильтрации других объектов или создать другие строки или даже другие типы вместо сценария: просто измените функции apply () и convert ()!(Ну да ладно, и некоторые общие подсказки :)).

Отказ от ответственности: код не был тщательно протестирован, только развернут для демонстрации и может иметь некоторые другие проблемы (такие как выделение ArrayList для новых коллекций).Вот почему обычно лучше использовать хорошо протестированные и отлаженные сторонние библиотеки!

0 голосов
/ 09 мая 2011

... но давайте тогда скажем, что я ищу лучший способ в Java без внешних библиотек?

В этом случае вам лучше всего написать циклы.

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

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

Ваши коллеги по работе будут склонны убивать вас за то, что вы тоже делаете это с помощью рефлексии.Лучший способ обеспечить ваше выживание с подключенными гонадами (:-)) - написать петли.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...