Если вы уверены, что selectedOption
конструктора Filter(T selectedOption)
не является нулевым. Вы можете использовать отражение.
public class Filter<T> {
private List<T> availableOptions = new ArrayList<T>();
private T selectedOption;
public Filter(T selectedOption) {
this.selectedOption = selectedOption;
for (T option : this.selectedOption.getClass().getEnumConstants()) { // INVALID CODE
availableOptions.add(option);
}
}
}
Надеюсь, это поможет.
Хороший ответ Джона (это понимание списка лучше, когда вы хотите повторять что-то несколько раз). Однако также стоит отметить, что вы должны использовать список, если вы хотите использовать любой из методов списка. Например, следующий код не будет работать:
def gen():
return (something for something in get_some_stuff())
print gen()[:2] # generators don't support indexing or slicing
print [5,6] + gen() # generators can't be added to lists
В основном, используйте выражение генератора, если все, что вы делаете, это итерация один раз. Если вы хотите сохранить и использовать сгенерированные результаты, то вам, вероятно, лучше понять список.
Поскольку производительность является наиболее распространенной причиной выбора одного над другим, я советую не беспокоиться об этом и просто выбрать один; если вы обнаружите, что ваша программа работает слишком медленно, тогда и только тогда вам следует вернуться и заняться настройкой своего кода.
Итерирование по выражению генератора или пониманию списка сделает то же самое. Однако понимание списка сначала создаст весь список в памяти, а выражение генератора создаст элементы на лету, так что вы можете использовать его для очень больших (а также бесконечные!) последовательности.
Используйте списочное понимание, когда результат должен повторяться многократно или когда скорость имеет первостепенное значение. Используйте выражения генератора, где диапазон большой или бесконечный.
Важным моментом является то, что понимание списка создает новый список. Генератор создает повторяемый объект, который будет «фильтровать» исходный материал на лету, когда вы будете использовать биты.
Представьте, что у вас есть файл журнала объемом 2 ТБ, называемый "принц-файлом", и вы хотите, чтобы содержимое и длина были для всех строк, начинающихся со слова "ВХОД".
Таким образом, вы пытаетесь начать с написания списка:
logfile = open("hugefile.txt","r")
entry_lines = [(line,len(line)) for line in logfile if line.startswith("ENTRY")]
Это отрывает весь файл, обрабатывает каждую строку и сохраняет совпадающие строки в вашем массиве. Следовательно, этот массив может содержать до 2 ТБ контента. Это много оперативной памяти, и, вероятно, не практично для ваших целей.
Таким образом, вместо этого мы можем использовать генератор, чтобы применить «фильтр» к нашему контенту. На самом деле никакие данные не читаются, пока мы не начнем итерацию по результату.
logfile = open("hugefile.txt","r")
entry_lines = ((line,len(line)) for line in logfile if line.startswith("ENTRY"))
Из нашего файла еще не было прочитано ни одной строки. Фактически, скажем, мы хотим отфильтровать наш результат еще дальше:
long_entries = ((line,length) for (line,length) in entry_lines if length > 80)
Еще ничего не было прочитано, но мы указали два генератора, которые будут действовать на наши данные, как мы хотим.
Давайте запишем наши отфильтрованные строки в другой файл:
outfile = open("filtered.txt","a")
for entry,length in long_entries:
outfile.write(entry)
Теперь мы читаем входной файл. Поскольку наш цикл for
продолжает запрашивать дополнительные строки, генератор long_entries
запрашивает строки из генератора entry_lines
, возвращая только те, длина которых превышает 80 символов. И, в свою очередь, генератор entry_lines
запрашивает строки (отфильтрованные как указано) от итератора logfile
, который, в свою очередь, читает файл.
Таким образом, вместо того, чтобы «выталкивать» данные в свою функцию вывода в виде полностью заполненного списка, вы даете функции вывода способ «извлекать» данные только тогда, когда это необходимо. В нашем случае это гораздо эффективнее, но не так гибко. Генераторы один путь, один проход; данные из файла журнала, который мы прочитали, немедленно удаляются, поэтому мы не можем вернуться к предыдущей строке. С другой стороны, нам не нужно беспокоиться о сохранении данных, как только мы закончим с ними.
Преимущество выражения генератора заключается в том, что оно использует меньше памяти, поскольку не создает весь список сразу. Выражения генератора лучше всего использовать, когда список является посредником, например, суммируя результаты или создавая из результатов выборку.
Например:
sum(x*2 for x in xrange(256))
dict( ((k, some_func(k) for k in some_list_of_keys) )
Преимущество состоит в том, что список не полностью сформирован, и, следовательно, мало памяти используется (и также должен быть быстрее)
Вы должны, Тем не менее, используйте понимание списка, когда желаемый конечный продукт является списком. Вы не собираетесь сохранять какую-либо память, используя выражения генератора, так как вам нужен сгенерированный список. Вы также получаете возможность использовать любые функции списка, например отсортированные или перевернутые.
Например:
reversed( [x*2 for x in xrange(256)] )
При создании генератора из изменяемого объекта (например, списка) следует помнить, что генератор будет оцениваться по состоянию списка во время использования генератора, а не во время создания генератора:
>>> mylist = ["a", "b", "c"]
>>> gen = (elem + "1" for elem in mylist)
>>> mylist.clear()
>>> for x in gen: print (x)
# nothing
Если есть шанс, что ваш список будет изменен (или изменяемый объект внутри этого списка), но вам нужно состояние при создании генератора, вам нужно вместо этого использовать понимание списка.
Я использую модуль Hadoop Mincemeat . Я думаю, что это отличный пример, чтобы принять к сведению:
import mincemeat
def mapfn(k,v):
for w in v:
yield 'sum',w
#yield 'count',1
def reducefn(k,v):
r1=sum(v)
r2=len(v)
print r2
m=r1/r2
std=0
for i in range(r2):
std+=pow(abs(v[i]-m),2)
res=pow((std/r2),0.5)
return r1,r2,res
Здесь генератор получает числа из текстового файла (размером до 15 ГБ) и применяет простую математику к этим числам, используя map-Reduce от Hadoop. , Если бы я не использовал функцию yield, а использовал бы понимание списка, для вычисления сумм и среднего значения потребовалось бы гораздо больше времени (не говоря уже о сложности пространства).
Hadoop - отличный пример использования всех преимуществ Генераторов.
Как насчет использования [(exp для x в iter)], чтобы получить пользу от обоих. Производительность от понимания генератора, а также методов списка
Иногда вы можете обойтись без функции tee из itertools , она возвращает несколько итераторов для одного и того же генератора, которые могут использоваться независимо.