Как перевести эту типизацию утки (Python) в дженерики Java? - PullRequest
3 голосов
/ 02 августа 2011

Рассмотрим в качестве примера следующую простую функцию Python:

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])

И вот оно в действии:

>>> 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 - кортеж, возвращаемое значение будет кортежем. (Эта последняя функция, безусловно, самая слабая, но она также меньше всего интересует меня для репликации в Java, поэтому я не стал делать ее более надежной.)

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

Спасибо!

Ответы [ 2 ]

4 голосов
/ 02 августа 2011

Одним из решений вопроса о типе ввода / вывода может быть использование класса Number и его подклассов вместе с подстановочными знаками.Если вы хотите принять любой тип числового аргумента, вы можете указать тип ввода: Number ИЛИ ? extends Number.Если входные данные являются списком, последняя форма имеет преимущество, поскольку она гарантирует, что каждый элемент списка имеет один и тот же тип (который должен быть подклассом Number).? известен как Подстановочный знак , а когда он выражен как ? extends Number, он является «Ограниченным подстановочным знаком» и может относиться только к подтипу ограничивающего типа.

Пример:

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

Это будет принимать список определенного подкласса Number, Number для параметра nlevels и возвращать список Number s

Что касается входного параметра функции, можно было бы ввести Method, хотя проверка типов в этой точке затрудняется, так как вы будете передавать данные ограниченного неизвестного параметра в Methodобъект.Я не совсем уверен, как это будет работать.

Что касается возвращаемого типа, можно было бы указать другой параметр, объект класса (вероятно, снова ? extends Number), который будет приведен к элементам списка (или преобразуется) в.

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

Это попытка возможного объявления вашей функции в Java.Реализация, однако, несколько сложнее.

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

Это не совсем то, что вы спросили, но могу ли я предложить попробовать Jython ? Вы сможете взять свой код Python и скомпилировать непосредственно в байт-код Java. Поскольку вы не использовали Java с 2001 года и, похоже, в настоящее время вы используете Python, вам может оказаться, что с Jython работать намного проще, чем с необходимостью заранее изучить все изменения в Java.

...