Этот ответ должен быть довольно коротким и сладким, чтобы ответить (часть) озаглавленного вопроса. Если вы хотите получить более подробный ответ, объясняющий, почему вы должны их там поместить, пожалуйста, перейдите здесь .
Общее правило для размещения typename
в основном, когда вы используете параметр шаблона, и хотите получить доступ к вложенному typedef
или с использованием псевдонима, например:
template
struct test {
using type = T; // no typename required
using underlying_type = typename T::type // typename required
};
Обратите внимание, что это также относится к метафункциям или вещи, которые также принимают общие параметры шаблона. Однако, если предоставленный параметр шаблона является явным типом, вам не нужно указывать typename
, например:
template
struct test {
// typename required
using type = typename std::conditional::type;
// no typename required
using integer = std::conditional::type;
};
Общие правила добавления определителя template
в основном аналогичны, за исключением они обычно включают шаблонные функции-члены (статические или другие) структуры / класса, которые сами шаблоны, например:
Учитывая эту структуру и функцию:
template
struct test {
template
void get() const {
std::cout << "get\n";
}
};
template
void func(const test& t) {
t.get(); // error
}
Попытка доступа t.get
изнутри функции приведет к ошибке:
main.cpp:13:11: error: expected primary-expression before 'int'
t.get();
^
main.cpp:13:11: error: expected ';' before 'int'
Таким образом, в этом контексте вам понадобится ключевое слово template
заранее и вызвать его так:
t.template get
Таким образом, компилятор будет анализировать это правильно, а не t.get < int
.
Необходимость выполнить итерации по списку многократно не изящна, по моему скромному мнению.
я, вероятно, создал бы функцию, которая позволяет делать:
twos, threes = countmatching(xrange(1,10),
lambda a: a % 2 == 0,
lambda a: a % 3 == 0)
начальная точка А была бы чем-то вроде этого:
def countmatching(iterable, *predicates):
v = [0] * len(predicates)
for e in iterable:
for i,p in enumerate(predicates):
if p(e):
v[i] += 1
return tuple(v)
Btw, "itertools рецепты" имеют рецепт для того, чтобы сделать во многом как Ваш alt4.
def quantify(seq, pred=None):
"Count how many times the predicate is true in the sequence"
return sum(imap(pred, seq))
Высокий звук 4! Но возможно необходимо осуществить рефакторинг код к функции, которая берет аргумент, который должен содержать делимое число (два и три). И затем у Вас мог быть лучший functionname.
def methodName(divNumber, r):
return sum(1 for v in r if v % divNumber == 0)
print methodName(2, xrange(1, 10))
print methodName(3, xrange(1, 10))
Вы могли использовать filter
функция.
Это фильтрует список (или строго повторяемое) создание нового списка, содержащего только объекты, для которых указанная функция оценивает к истинному.
r = xrange(1, 10)
def is_div_two(n):
return n % 2 == 0
def is_div_three(n):
return n % 3 == 0
print len(filter(is_div_two,r))
print len(filter(is_div_three,r))
Это хорошо, поскольку это позволяет Вам, сохраняют Вашу логику статистики содержавшейся в функции, и намерение эти filter
должно быть довольно ясным.
Я выбрал бы маленький вариант Вашего (высокий звук 4):
def count(predicate, list):
print sum(1 for x in list if predicate(x))
r = xrange(1, 10)
count(lambda x: x % 2 == 0, r)
count(lambda x: x % 3 == 0, r)
# ...
, Если Вы хотите изменить то, что делает количество, измените его реализацию в одном месте.
Примечание: так как Ваши предикаты сложны, Вы, вероятно, захотите определить их в функциях вместо лямбд. И таким образом, Вы, вероятно, захотите поместить все это в класс, а не глобальное пространство имен.
Хорошо Вы могли сделать одно понимание/выражение списка, чтобы получить ряд кортежей с тем тестом статистики в них и затем уменьшить это вниз для получения сумм.
r=xrange(10)
s=( (v % 2 == 0, v % 3 == 0) for v in r )
def add_tuples(t1,t2):
return tuple(x+y for x,y in zip(t1, t2))
sums=reduce(add_tuples, s, (0,0)) # (0,0) is starting amount
print sums[0] # sum of numbers divisible by 2
print sums[1] # sum of numbers divisible by 3
Используя выражение генератора и т.д. должен означать, что Вы только пробежите итератор однажды (если не уменьшат, делает что-либо нечетное?). В основном Вы сделали бы, отображают/уменьшают...
Истинные булевские переменные принуждены к целым числам единицы и ложным булевским переменным для обнуления целых чисел. Таким образом, если Вы рады использовать scipy или numpy, сделайте массив целых чисел для каждого элемента Вашей последовательности, каждый массив, содержащий один элемент для каждого из Ваших тестов и сумму по массивам. Например,
>>> sum(scipy.array([c % 2 == 0, c % 3 == 0]) for c in xrange(10))
array([5, 4])
Я определенно посмотрел бы массив numpy вместо повторяемого списка, если у Вас просто есть числа. Вы почти наверняка сможете сделать то, что Вы хотите с некоторой краткой арифметикой на массиве.
Не столь краткий, как Вы ищете, но более эффективный, это на самом деле работает с любым повторяемым, не только iterables Вы может циклично выполниться многократно, и можно развернуть вещи проверить на, не усложняя его далее:
r = xrange(1, 10)
counts = {
2: 0,
3: 0,
}
for v in r:
for q in counts:
if not v % q:
counts[q] += 1
# Or, more obscure:
#counts[q] += not v % q
for q in counts:
print "%s's: %s" % (q, counts[q])
from itertools import groupby
from collections import defaultdict
def multiples(v):
return 2 if v%2==0 else 3 if v%3==0 else None
d = defaultdict(list)
for k, values in groupby(range(10), multiples):
if k is not None:
d[k].extend(values)
Вдохновленный ударом OO выше, я должен был попробовать руки один также (хотя это - путь излишество для проблемы, я пытаюсь решить :)
class Stat(object):
def update(self, n):
raise NotImplementedError
def get(self):
raise NotImplementedError
class TwoStat(Stat):
def __init__(self):
self._twos = 0
def update(self, n):
if n % 2 == 0: self._twos += 1
def get(self):
return self._twos
class ThreeStat(Stat):
def __init__(self):
self._threes = 0
def update(self, n):
if n % 3 == 0: self._threes += 1
def get(self):
return self._threes
class StatCalculator(object):
def __init__(self, stats):
self._stats = stats
def calculate(self, r):
for v in r:
for stat in self._stats:
stat.update(v)
return tuple(stat.get() for stat in self._stats)
s = StatCalculator([TwoStat(), ThreeStat()])
r = xrange(1, 10)
print s.calculate(r)
Высокий звук 3, по причине, что это не использует память, пропорциональную количеству "хитов". Учитывая патологический случай как xrange (one_trillion), многие из других предлагаемых решений перестали бы работать плохо.
Идея здесь состоит в том, чтобы использовать сокращение для предотвращения повторенных повторений. Кроме того, это не создает дополнительных структур данных, если память является проблемой для Вас. Вы запускаете со словаря со своими счетчиками ({'div2': 0, 'div3': 0}
) и увеличиваете их вдоль повторения.
def increment_stats(stats, n):
if n % 2 == 0: stats['div2'] += 1
if n % 3 == 0: stats['div3'] += 1
return stats
r = xrange(1, 10)
stats = reduce(increment_stats, r, {'div2': 0, 'div3': 0})
print stats
, Если бы Вы хотите считать что-нибудь более сложным, чем делители, было бы уместно использовать больше объектно-ориентированного подхода (с теми же преимуществами), инкапсулируя логику для извлечения статистики.
class Stats:
def __init__(self, div2=0, div3=0):
self.div2 = div2
self.div3 = div3
def increment(self, n):
if n % 2 == 0: self.div2 += 1
if n % 3 == 0: self.div3 += 1
return self
def __repr__(self):
return 'Stats(%d, %d)' % (self.div2, self.div3)
r = xrange(1, 10)
stats = reduce(lambda stats, n: stats.increment(n), r, Stats())
print stats
укажите на любые ошибки.
@Henrik: Я думаю, что первый подход менее удобен в сопровождении, так как необходимо управлять инициализацией словаря в одном месте и обновлением в другом, а также имеющий необходимость использовать строки для обращения к каждой статистике (вместо того, чтобы иметь атрибуты). И я не думаю, что OO является излишеством в этом случае, поскольку Вы сказали, что предикаты и объекты будут сложны в Вашем приложении. На самом деле, если бы предикаты были действительно просты, то я даже не потрудился бы использовать словарь, единственный список фиксированного размера был бы очень хорошо. Аплодисменты :)