Самый элегантный способ извлечь данные из нескольких списков в новый в Java? - PullRequest
0 голосов
/ 21 августа 2009

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

У меня есть код, который работает так:

class A {
    public List<SomeType> getOneSet() { ... }
    public List<SomeType> getAnotherSet() { ... }
}

class B {
    public static OtherType convert(SomeType input) { ... }
}

// ...

A a = new A();
List<OtherType> rgResults = new ArrayList<OtherType>();

А теперь будет следовать эквиваленту двух одинаковых for циклов, например:

for (SomeType input : a.getOneSet()) {
    rgResults.add(B.convert(input);
}

for (SomeType input : a.getAnotherSet()) {
    rgResults.add(B.convert(input);
}

Это работает, но это, конечно, дублирование кода. Если код внутри цикла становится немного более сложным или имеется более двух наборов, это неприемлемо.

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

Например, мне бы понравилось следующее, которое не сработало, потому что у меня не может быть массивов обобщений:

for (List<SomeType> rgSrc : new List<SomeType>[] { a.getOneSet(), a.getAnotherSet() } ) {
    for (SomeType src : rgSrc) {
        rgResults.add(B.convert(src));
    }
}

Ответы [ 6 ]

6 голосов
/ 21 августа 2009

Попробуйте IteratorUtils . У этого есть метод, чтобы связать итераторы.

2 голосов
/ 21 августа 2009

Следуя принципу «используй чужой код», я думаю, что самая чистая реализация, которую ты найдешь, будет в Итерируемом классе Коллекций Google .

Вы можете сделать:

for (SomeType input : Iterables.concat(a.getOneSet(), a.getAnotherSet()) {
  rgResults.add(B.convert(input);
}

Или, если вы переписываете B как Функция и используете Списки :

rgResults = Lists.transform(
    Lists.newArrayList(Iterables.concat(a.getOneSet(), a.getAnotherSet()), 
    new B());

и все готово!

2 голосов
/ 21 августа 2009

Функция ListUtils union (java.util.List list1, java.util.List list2) из API сбора общих файлов Apache выполнит работу ==> объединение , а также =]

2 голосов
/ 21 августа 2009

Попробуйте что-то вроде этого:

interface Getter<E, I> 
{
  public E get(I item);
}

public static <T extends Collection<E>, I, E> T convert(T target, Collection<I> source, Getter<E, I> getter)
{
  for (I item : source)
  {
    target.add(getter.get(item));
  }

  return target;
}

List<String> strings = CollectionUtil.convert(
  new ArrayList<String>(someItems.size)
  someItems,
  new Getter<String, MyClass>() 
  {
    public String get(MyClass item)
    {
      return item.toString();
    }
  }
);

Вы просто вводите Getter по мере необходимости в зависимости от разговора, который хотите сделать.

1 голос
/ 21 августа 2009

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

for (List<SomeType> rgSrc : new List[] { a.getOneSet(), a.getAnotherSet() } ) {
    for (SomeType src : rgSrc) {
        rgResults.add(B.convert(src));
    }
}
1 голос
/ 21 августа 2009

Для решения, не использующего циклы вообще, вы можете использовать функцию преобразования lambdaj:

см. http://code.google.com/p/lambdaj/wiki/LambdajFeatures

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