Кросс-продукт калькулятор на Java - PullRequest
2 голосов
/ 04 августа 2011

Я пробираюсь через книгу Норвига по AIP .В нем есть упражнение по написанию функции для нескольких продуктов -

(defun cross-product (fn list-1 list-2)
  (mappend #'(lambda (y)
               (mapcar #'(lambda (x)
                           (funcall fn y x))
                       list-2))
           list-1))

(defun mappend (fn the-list)
  (if (null the-list)
      nil
      (append (funcall fn (first the-list))
              (mappend fn (rest the-list)))))

Я пытаюсь написать реализацию на Java -

interface Function<T1, T2, T3> {
    public T3 function(T1 t1, T2 t2);
}

public class CrossProduct<T1, T2> {
    private List<T1> list1;
    private List<T2> list2;

    public CrossProduct(List<T1> t1, List<T2> t2) {
         this.list1 = t1;
         this.list2 = t2;
    }

    public <T3> List<T3> calculate(Function<T1, T2, T3> fn) {
    List product = new ArrayList();
    for (int i = 0; i < list1.size(); i++)
        for (int j = 0; j < list2.size(); j++)
            product.add(fn.function(list1.get(i), list2.get(j)));
    return product;
}

}

Использование-

@Test
public void testWithStrings() {
    List<String> list1 = new ArrayList<String>();
    list1.add("6");
    list1.add("8");

    List<String> list2 = new ArrayList<String>();
    list2.add("2");
    list2.add("3");

    List<String> product = new CrossProduct<String, String>(list1, list2)
            .<String> calculate(new Function<String, String, String>() {
                public String function(String x, String y) {
                    return (String) x + (String) y;
                }

            });

    Assert.assertEquals("62", product.get(0));
    Assert.assertEquals("63", product.get(1));
    Assert.assertEquals("82", product.get(2));
    Assert.assertEquals("83", product.get(3));
}

Есть ли лучший способ сделать это?

Ответы [ 2 ]

1 голос
/ 04 августа 2011

Кажется немного произвольным определить ваш класс CrossProduct таким образом: почему переменные-члены списка аргументов, тогда как fn является параметром метода? На самом деле, почему CrossProduct вообще класс? Список перекрестных произведений is a, но это не подтип списка, поскольку данный список может одновременно

  1. можно выразить как перекрестное произведение многими различными способами, а
  2. не были созданы с использованием функции crossproduct.

Не вполне естественно думать о «перекрестном произведении» как о типе, ИМО.

Я бы, наверное, сделал что-то вроде

public class ListFunctions {
    public static <T1, T2, T3> List<T3> crossProduct(List<T1> list1, List<T2> list2, Function<T1, T2, T3> fn) {
        List<T3> product = new ArrayList<T3>();
        for (int i = 0; i < list1.size(); i++)
          for (int j = 0; j < list2.size(); j++)
            product.add(fn.function(list1.get(i), list2.get(j)));
        return product;
    }
}

Если бы вы по какой-то причине захотели определить класс CrossProduct (например, реализовать ленивую оценку, как предложил Салман), я бы сказал, что лучше использовать все три аргумента в качестве переменных-членов и реализовать класс List, например

public class CrossProduct<T1, T2, T3> implements List<T3> {
    public CrossProduct(T1 list1, T2 list2, Function<T1, T2, T3> fn) {
        // remember args...
    }
    // etc...
}
1 голос
/ 04 августа 2011

Я не знаю точно, какие параметры вы хотели бы улучшить. Однако я бы сказал, что мне не нравится размер списка N * M, поскольку он может быть слишком большим. Если бы я знал, что список результатов может быть неизменным, то я бы реализовал свой собственный Список, который вычисляет product(l1(i), l2(j)) только при вызове result.get(i*M+j-1). Поэтому я не держу длинный список (возможно, просто небольшой кеш, если необходимо).

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