Большая часть pythonic способа считать соответствие элементам в чем-то повторяемом

Этот ответ должен быть довольно коротким и сладким, чтобы ответить (часть) озаглавленного вопроса. Если вы хотите получить более подробный ответ, объясняющий, почему вы должны их там поместить, пожалуйста, перейдите здесь .


Общее правило для размещения 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.

16
задан Gilles 'SO- stop being evil' 30 April 2012 в 21:12
поделиться

12 ответов

Необходимость выполнить итерации по списку многократно не изящна, по моему скромному мнению.

я, вероятно, создал бы функцию, которая позволяет делать:

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))
18
ответ дан 30 November 2019 в 17:28
поделиться

Высокий звук 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))
6
ответ дан 30 November 2019 в 17:28
поделиться

Вы могли использовать 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
ответ дан 30 November 2019 в 17:28
поделиться

Я выбрал бы маленький вариант Вашего (высокий звук 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)
# ...

, Если Вы хотите изменить то, что делает количество, измените его реализацию в одном месте.

Примечание: так как Ваши предикаты сложны, Вы, вероятно, захотите определить их в функциях вместо лямбд. И таким образом, Вы, вероятно, захотите поместить все это в класс, а не глобальное пространство имен.

2
ответ дан 30 November 2019 в 17:28
поделиться

Хорошо Вы могли сделать одно понимание/выражение списка, чтобы получить ряд кортежей с тем тестом статистики в них и затем уменьшить это вниз для получения сумм.


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

Используя выражение генератора и т.д. должен означать, что Вы только пробежите итератор однажды (если не уменьшат, делает что-либо нечетное?). В основном Вы сделали бы, отображают/уменьшают...

1
ответ дан 30 November 2019 в 17:28
поделиться

Истинные булевские переменные принуждены к целым числам единицы и ложным булевским переменным для обнуления целых чисел. Таким образом, если Вы рады использовать scipy или numpy, сделайте массив целых чисел для каждого элемента Вашей последовательности, каждый массив, содержащий один элемент для каждого из Ваших тестов и сумму по массивам. Например,

>>> sum(scipy.array([c % 2 == 0, c % 3 == 0]) for c in xrange(10))
array([5, 4])
1
ответ дан 30 November 2019 в 17:28
поделиться

Я определенно посмотрел бы массив numpy вместо повторяемого списка, если у Вас просто есть числа. Вы почти наверняка сможете сделать то, что Вы хотите с некоторой краткой арифметикой на массиве.

0
ответ дан 30 November 2019 в 17:28
поделиться

Не столь краткий, как Вы ищете, но более эффективный, это на самом деле работает с любым повторяемым, не только 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])
0
ответ дан 30 November 2019 в 17:28
поделиться
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)
0
ответ дан 30 November 2019 в 17:28
поделиться

Вдохновленный ударом 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)
0
ответ дан 30 November 2019 в 17:28
поделиться

Высокий звук 3, по причине, что это не использует память, пропорциональную количеству "хитов". Учитывая патологический случай как xrange (one_trillion), многие из других предлагаемых решений перестали бы работать плохо.

0
ответ дан 30 November 2019 в 17:28
поделиться

Идея здесь состоит в том, чтобы использовать сокращение для предотвращения повторенных повторений. Кроме того, это не создает дополнительных структур данных, если память является проблемой для Вас. Вы запускаете со словаря со своими счетчиками ({'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 является излишеством в этом случае, поскольку Вы сказали, что предикаты и объекты будут сложны в Вашем приложении. На самом деле, если бы предикаты были действительно просты, то я даже не потрудился бы использовать словарь, единственный список фиксированного размера был бы очень хорошо. Аплодисменты :)

0
ответ дан 30 November 2019 в 17:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: