2

私はAIP に関する Norvig の本を読み進めています。クロス積関数の記述に関する演習があります -

(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));
}

これを行うより良い方法はありますか?

4

2 に答える 2

1

どのパラメータを改善したいのか正確にはわかりません。ただし、N*M のリスト サイズは大きすぎる可能性があるため、好きではありません。結果リストが不変であることがわかっている場合は、呼び出されたproduct(l1(i), l2(j))ときだけを計算する独自の List を実装します。result.get(i*M+j-1)そのため、長いリストは保持していません (必要に応じて小さなキャッシュを保存するだけかもしれません)。

于 2011-08-04T11:25:44.717 に答える
1

クラスをそのように定義するのは少し恣意的なように思えますCrossProduct: なぜ list args メンバー変数なのに対し、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(たとえば、salman が提案したように遅延評価を実装するため)、メンバー変数として 3 つの引数すべてを持ち、クラスを実装する方がオブジェクト指向だと思いますList

public class CrossProduct<T1, T2, T3> implements List<T3> {
    public CrossProduct(T1 list1, T2 list2, Function<T1, T2, T3> fn) {
        // remember args...
    }
    // etc...
}
于 2011-08-04T14:45:58.067 に答える