Я поздний участник этого вопроса, но я хочу упомянуть здесь, что строка «Программа для интерфейса, а не реализация» имела хорошее обсуждение в книге шаблонов дизайна GoF (Gang of Four).
На стр. 18:
Программа для интерфейса, а не для реализации
Не объявляйте переменные экземплярами конкретных конкретных классов. Вместо этого зафиксируйте только интерфейс, определенный абстрактным классом. Вы найдете это общей темой шаблонов проектирования в этой книге.
blockquote>и выше этого, это началось с:
Есть два преимущества манипулировать объектами исключительно с точки зрения интерфейса, определенного абстрактными классами:
blockquote>
- Клиенты не знают о конкретных типах объектов, которые они используют, если объекты соответствуют интерфейсу, который ожидают клиенты.
- Клиенты не знают о классах, которые реализуют эти объекты. Клиенты знают только об абстрактном классе (ов), определяющем интерфейс.
Так, другими словами, не записывайте его в свои классы, чтобы он имел метод
quack()
для уток, а затем методbark()
для собак, поскольку они слишком специфичны для конкретной реализации класса (или подкласса). Вместо этого напишите метод, используя имена, которые являются достаточно общими для использования в базовом классе, напримерgiveSound()
илиmove()
, чтобы их можно было использовать для уток, собак или даже автомобилей, а затем для клиента вашего классы могут просто сказать.giveSound()
, а не думать о том, использовать лиquack()
илиbark()
или даже определить тип перед выдачей правильного сообщения, которое должно быть отправлено объекту.
Вот один из способов с ave
:
ave(df$a, cumsum(c(F, diff(df$a) < 0)), FUN=seq_along) - 1
[1] 0 1 2 3 0 1 2 3 4 5 6 0 1 0
Мы можем получить текущее количество, сгруппированное по diff(df$a) < 0
. Каковы позиции в векторе, которые меньше их предшественников. Мы добавим c(F, ..)
для учета первой позиции. Суммарная сумма этого вектора создает индекс для группировки. Функция ave
может выполнять функцию по этому индексу, мы используем seq_along
для текущего подсчета. Но поскольку он начинается с 1, мы вычитаем один ave(...) - 1
, чтобы начать с нуля.
Аналогичный подход с использованием dplyr
:
library(dplyr)
df %>%
group_by(cumsum(c(FALSE, diff(a) < 0))) %>%
mutate(row_number() - 1)
a <- c(1,2,3,4,2,3,4,5,8,9,10,1,2,1)
f <- c(0, diff(a)>0)
ifelse(f, cumsum(f), f)
, что он не перезагружен. с сбросом:
unlist(tapply(f, cumsum(c(0, diff(a) < 0)), cumsum))
Вам не нужно dplyr:
fun <- function(x) {
test <- diff(x) > 0
y <- cumsum(test)
c(0, y - cummax(y * !test))
}
fun(df$a)
[1] 0 1 2 3 0 1 2 3 4 5 6 0 1 0
dplyr
(в соответствии с тегом)df %>% group_by(cumsum(c(FALSE, diff(a) < 0))) %>% mutate(row_number() - 1)
– David Arenburg 7 October 2015 в 13:59