Вычисление нескольких результатов из одной итерации массива - PullRequest
3 голосов
/ 06 апреля 2011

Я хочу вычислить несколько функций за одну итерацию массива или списка, но может потребоваться динамический рост списка функций.Например, я мог бы хотеть вычислить min и max, а затем также захотеть функцию усреднения (или любую другую функцию линейной сложности) когда-нибудь позже.Итак, я мог бы хотеть иметь высокоуровневую спецификацию (используя некоторые функции, называемые addFunc и applyAllFuncs, такие как

funcs = emptyFunctionList;    # no functions in funcs "list" yet
funcs = addFunc (min, funcs);  # add minimum function
funcs1 = addFunc (max, funcs);  # add maximum function 

answers1 = applyAllFuncs (funcs1, myArray);     

funcs2 = addFunc (avg, funcs);  # add average function 

answers2 = applyAllFuncs (funcs2, myArray); 

. Я могу сделать это довольно легко на функциональном языке, создав «суперфункцию»«из этих функций, которые передаются в foldl, и метапрограммирование может быть механизмом, позволяющим сделать это намного более эффективно в Haskell / C ++, но хотел знать, есть ли эффективный и не очень сложный способ, которым это обычносделано (или может быть сделано) в стандартной Java (без необходимости много делать для моделирования / реализации функций более высокого уровня).

Ответы [ 3 ]

1 голос
/ 09 апреля 2011

Вот полный рабочий код Java, эквивалентный функциональному псевдокоду, который вы дали в своем посте:

import java.util.*;

interface Function1<A, B> {
  public B apply(final A a);
}

class Main {
  public static <A, B> List<Function1<A, B>> addFunc(final Function1<A, B> f, final List<Function1<A, B>> fs) {
    final List<Function1<A, B>> gs = new ArrayList<Function1<A, B>>();
    gs.addAll(fs);
    gs.add(f);
    return gs;
  }

  public static <A, B> List<B> applyAllFuncs(final List<Function1<List<A>, B>> fs, final List<A> as) {
    final List<B> bs = new ArrayList<B>();
    for(final Function1<List<A>, B> f : fs) {
      bs.add(f.apply(as));
    }
    return bs;
  }

  public static Function1<List<Double>, Double> min = new Function1<List<Double>, Double>() {
    public Double apply(final List<Double> xs) {
      double mx = xs.get(0);
      for(final Double x : xs) {
        if(x < mx) {
          mx = x;
        }
      }
      return mx;
    }
  };

  public static Function1<List<Double>, Double> avg = new Function1<List<Double>, Double>() {
    public Double apply(final List<Double> xs) {
      double sum = 0;
      for(final Double x : xs) {
        sum += x;
      }
      return sum / xs.size();
    }
  };

  public static Function1<List<Double>, Double> max = new Function1<List<Double>, Double>() {
    public Double apply(final List<Double> xs) {
      double mx = xs.get(0);
      for(final Double x : xs) {
        if(x > mx) {
          mx = x;
        }
      }
      return mx;
    }
  };

  public static void main(final String[] args) {
    final List<Double> myArray = Arrays.asList(3.0, 8, 1, 2, 9);
    List<Function1<List<Double>, Double>> funcs = new ArrayList<Function1<List<Double>, Double>>();
    funcs = addFunc(min, funcs);
    final List<Function1<List<Double>, Double>> funcs1 = addFunc(max, funcs);
    final List<Double> answers = applyAllFuncs(funcs1, myArray);
    final List<Function1<List<Double>, Double>> funcs2 = addFunc(avg, funcs);
    final List<Double> answers2 = applyAllFuncs(funcs2, myArray);
    System.out.println(answers + "\n" + answers2);
  }
}

Многого из этого стандартного шаблона можно было бы избежать, если вы используете уже существующие библиотеки функционального программирования для Java, напримеркак Функциональная Java или та, что предлагается GridGain.

Не многое из этого оптимизировано, поскольку JVM никогда не предназначалась для такого рода вещей.Scala, который является функциональным языком в JVM, использует те же методы, что и выше, для реализации лямбда-выражений и функций более высокого порядка и обеспечивает производительность на уровне Java.Тем не менее, я советую вам профилировать код и решить, удовлетворяет ли он требованиям производительности вашего конкретного варианта использования.

0 голосов
/ 08 апреля 2011

Вы можете использовать какой-нибудь шаблон Stategy:

public interface Function{
    public void Compute();
}

public Function1 implements Function{
   public void Compute(){
       System.out.println("This is Function1");
   }
}

public Function2 implements Function{
   public void Compute(){
       System.out.println("This is Function2");
   }
}

После этого объявите контейнер функции:

ArrayList<Function> functions = new ArrayList<Function>();
functions.add(new Function1());
functions.add(new Function2());

ArrayList<Object> someData = new ArrayList<Object>();
Something.execute(someData,functions);
0 голосов
/ 06 апреля 2011

Создайте свой собственный сгиб:
Иметь метод, который принимает список и список функций для запуска в списке.
Список функций для запуска в списке может быть просто ArrayList<XFunction>, гдеXFunction - это определенный вами класс, имеющий метод (скажем, run(...)), и вы можете создать его анонимную реализацию для каждой функции.

Пример:

list.add(new XFunction(){ 
   run(ArrayList<int> numbers){ 
      return numbers.size(); 
       }
   }

Какой изКонечно, это не функция, которая решает что-либо, но вы понимаете,

...