我正在解决算法问题,我想编写可应用于集合的自定义函数和谓词。最近,我开始使用Google Collections,这对于这项任务来说非常棒。
我想以同样的方式使用BigInteger和BigDecimal,因为我会使用任何其他数字。在没有思考应该如何完成的情况下,我决定进行额外的抽象层(E类)。
如果不清楚我想做什么,这是一个例子:
I.range(1,999).multiplication(I.range(1,999)).palindromes().max().echo(2);
E类定义为:
public class E<T extends Number & Comparable<? super T>> extends Number implements Comparable<E<T>> {//...
C类定义为:
public class C<T extends E<NC>, NC extends Number & Comparable<? super NC>> implements Collection<T> {
这是我想在C级工作的。
public Collection<T> multiplication(T value) {
return Collections2.transform(this, new Function<T, T>() {
@Override
public T apply(T in) {
return in.times(value);
}
});
}
在我使用以下代码之前,在E类中
/** Multiplies 2 numbers */
public E<?> times(E<?> elem) {
if (this.value == null || elem.value == null) return E.Null();
if (this.value instanceof Integer) {
return E.with(I, this.intValue() * elem.intValue());
} else if (this.value instanceof Long) {
return E.with(L, this.longValue() * elem.longValue());
} else if (this.value instanceof Float) {
return E.with(F, this.floatValue() * elem.floatValue());
} else if (this.value instanceof Double) {
return E.with(D, this.doubleValue() * elem.doubleValue());
} else if (this.value instanceof BigInteger) {
return E.with(BI, this.BigIntegerValue().multiply(
elem.BigIntegerValue()));
} else if (this.value instanceof BigDecimal) { return E.with(BD,
this.BigDecimalValue().multiply(elem.BigDecimalValue())); }
return E.Null();
}
我应该更改什么,以便编写自定义函数和谓词将涉及最少量的'suckiness'。
一口井,将C改为:
public class C<T extends E<?>> extends ArrayList<T> {
只是抑制了像
这样的通用通配符强制转换警告public Collection<T> multiplication(Collection<T> value) {
C<T> result = new C<T>();
for (T t : value)
result.addAll(multiplication(t));
return result;
}
public Collection<T> multiplication(final T value) {
return Collections2.transform(this, new Function<T, T>() {
@SuppressWarnings("unchecked")
@Override
public T apply(T in) {
return (T) in.times(value);
}
});
}
因此,如果类型匹配,则可行。
答案 0 :(得分:3)
您可以使用Scala吗?
它是一种可以在jdk下运行的函数式编程语言。
答案 1 :(得分:3)
package euler;
import fj.F;
import static fj.Function.flip;
import fj.data.Stream;
import static fj.data.Stream.range;
import static fj.function.Integers.multiply;
import static fj.function.Integers.add;
import static fj.pre.Equal.charEqual;
import static fj.pre.Equal.streamEqual;
import static fj.pre.Ord.intOrd;
import static fj.pre.Show.intShow;
/**
* Find the largest palindrome made from the product of two 3-digit numbers.
*/
public class Problem4
{private static final F<Integer, Boolean> palindrome =
new F<Integer, Boolean>() {public Boolean f(final Integer i)
{final Stream<Character> s = intShow.show(i);
return streamEqual(charEqual).eq(s.reverse(), s);}}
public static void main(final String[] a)
{final Stream<Integer> xs = range(100, 999);
intShow.println(xs.tails().bind(xs.zipWith(multiply)).filter(palindrome)
.foldLeft1(intOrd.max));}}
编辑以下是noise-filtering glasses的内容:
palindrome i = s == reverse s
where s = show i
main = putStrLn . maximum . filter palindrome $ tails xs >>= zipWith (*) xs
where xs = [100..999]
答案 2 :(得分:2)
虽然我同意评论这不是Java的小巷,但解决这个问题的一种方法可能是初始化这样的地图:
public interface Multiply<T> {
T multiply(T one, T two);
}
//In some initializaiton code, say a static initializer
Map<Class<?>, Multiply<?>> map = newHashMap(); //That is the method from Google Collections
map.put(Integer.class, new Multiply<Integer>(){
Integer multiply(Integer one, Integer two) {
return one * two;
}
});
等。对于每个案例。然后在你的代码中,(使用适当的空值检查):
Multiply mult = map.get(this.value.getClass());
Object val = mult.multiply(this.value, elem.value));
请注意,这里的原始类型是故意的,我不得不考虑是否可以这样做,并保持一切通用。反正不容易。
但是考虑到val类,你可以检索一个合适的E。
这不完全是我的头脑,所以我没有测试过一些潜在的通用问题。
答案 3 :(得分:1)
你可以使用反射。根据类的名称,找到方法并调用它。例如,对于“BigInteger”,您可以调用“BigIntegerValue”等等。
在java中处理不同的原始类型非常烦人,我不确定它是否可以轻松完成。你可能会失败一段时间,直到你做对了。也许你可以创建一个通用的Number类来抽象大小之间的差异(比如int,long,short等)和类型(整数,小数等),就像 cool 语言一样(Ruby,Smalltalk)例如)。根据结果的结果,您可以切换内部表示。例如,如果整数操作溢出,则切换为long。或者如果在操作中使用浮点数,则在内部切换到浮点数。但从外面来看,它只是一个数字。这会让你的其他课程更容易。
另一种方法是,您可以编写代码生成器来为您编写所有这些唠叨案例。它不应该太复杂。
答案 4 :(得分:1)
我相信Scala可能是您解决问题的最佳解决方案。
相反,如果您有义务使用Java,请在http://code.google.com/p/lambdaj/处查看lambdaj
你会发现你所需要的东西中最重要的部分已经在那里实现了。
答案 5 :(得分:0)
Clojure是一种类似于lisp的函数式语言,可以在jvm上运行。它有 bignums,比率和bigdecimals与传统的无类型lisp语义。