如何将这种鸭子式(Python)转换为Java泛型?

How to translate this duck-typing (Python) to Java generics?

通过示例考虑以下简单的Python函数:

1
2
3
4
5
6
7
8
def quantize(data, nlevels, quantizer=lambda x, d: int(floor(x/d))):
    llim = min(data)
    delta = (max(data) - llim)/(nlevels - 1) # last level x == max(data) only
    y = type(data)
    if delta == 0:
        return y([0] * len(data))
    else:
        return y([quantizer(x - llim, delta) for x in data])

它在起作用:

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> from random import random
>>> data = [10*random() for _ in range(10)]
>>> data
[6.6181668777075018, 9.0511321773967737, 1.8967672216187881, 7.3396890304913951,
4.0566699095012835, 2.3589022034131069, 0.76888247730320769, 8.994874996737197,
7.1717500363578246, 2.887112256757157]
>>> quantize(data, nlevels=5)
[2, 4, 0, 3, 1, 0, 0, 3, 3, 1]
>>> quantize(tuple(data), nlevels=5)
(2, 4, 0, 3, 1, 0, 0, 3, 3, 1)
>>> from math import floor
>>> quantize(data, nlevels=5, quantizer=lambda x, d: (floor(x/d) + 0.5))
[2.5, 4.5, 0.5, 3.5, 1.5, 0.5, 0.5, 3.5, 3.5, 1.5]

这个函数当然有缺陷-一方面,它不验证参数,并且应该更聪明地设置返回值的类型-但它的优点是,不管数据中的元素是否为正,它都将起作用整数或浮点数或其他一些数字类型。同样,默认情况下,它返回一个整数列表,不过,通过传递适当的函数作为可选的量化参数,可以将此类型更改为其他类型。此外,如果data参数是一个列表,则返回的值将是一个列表;如果data是一个元组,则返回的值将是一个元组。 (这最后一个功能当然是最弱的功能,但是它也是我对用Java复制最不感兴趣的功能,因此我没有费心使其功能更强大。)

我想编写一个等效于Java的有效函数,这意味着要弄清楚如何避免Java的输入。自从我学习Java(以前)以来,泛型就被引入了该语言。我曾尝试学习Java泛型,但发现它们非常难以理解。我不知道这是由于早发性衰老,还是因为自从我上一次编程(大约在2001年)以来Java的复杂性急剧增长,但是我发现有关此主题的每一页都比以前更混乱一。如果有人可以向我展示如何用Java做到这一点,我将非常感激。

谢谢!


输入/输出类型问题的一种解决方案可能是使用Number类及其子类以及通配符。如果要接受任何类型的数值参数,则可以将输入类型指定为Number? extends Number。如果输入是列表,则后一种形式具有优势,因为它将确保列表的每个元素都属于同一类型(必须是Number的子类)。 ?被称为通配符,当将其表示为? extends Number时,它是"有界通配符",并且只能引用边界类型的子类型。

例:

1
public List<Number> func(List<? extends Number> data, Number nlevels)

这将使用Number的特定子类的列表,nlevels参数的Number并返回Number的列表

对于函数输入参数,尽管此时进行类型检查变得困难,但仍可能输入Method,因为您将把未知的有界参数的数据传递给Method对象。我不确定这将如何工作。

至于返回类型,可以指定另一个参数,即列表元素将被转换(或转换为)的类对象(可能再次为? extends Number)。

1
2
3
4
public List<? extends Number> quantize(List<? extends Number> data,
                                       Number nlevels,
                                       Method quantizer,
                                       Class<? extends Number> returnType)

这是尝试在Java中声明功能的一种尝试。但是,实现有些复杂。


这不是您所要的,但我可以建议尝试Jython吗?您将可以使用Python代码并将其直接编译为Java字节码。由于您自2001年以来就没有使用过Java,而如今您似乎正在使用Python,因此您可能会发现Jython的工作要比不得不事先掌握Java的所有更改要容易得多。