提高寻找“I increasing dice roll sequences”的速度

Increase speed in finding "Ιncreasing dice roll sequences"

问题是有多少个 9 次掷骰的序列在增加(例如 223444556)。好的,我知道 choose(14,9) 给出了答案,但我只是想玩玩 dplyr。

一种快速但不优雅的方式:

library(tidyverse)

expand.grid(data.frame(matrix(rep(1:6,9),ncol=9))) %>% 
 filter(X1<=X2 & X2<=X3 &X3<=X4 &X4<=X5 &X5<=X6 &X6<=X7 &X7<=X8 &X8<=X9) %>% tally

我尝试了以下两种选择(没有明确引用变量名),但它们都非常慢(而且很耗内存)。你能帮我用 tidyverse 优化我的代码吗?

 expand_grid(!!!data.frame(matrix(rep(1:6,9),ncol=9))) %>% 
  rownames_to_column(var = "grp") %>% 
  mutate(grp = as.numeric(grp)) %>% 
  pivot_longer (cols=!grp) %>% 
  group_by(grp) %>% 
  mutate(prev = lag(value)) %>% 
  filter(!is.na(prev)) %>% 
  transmute(dif=value-prev) %>% 
  summarize(res = all(dif >=0)) %>% 
  group_by(res) %>% summarize(n=n())


 9 %>% 
    rerun(1:6) %>% crossing(!!!.,.name_repair = "minimal") %>%
    set_names(glue::glue('c{1:ncol(.)}')) %>% 
    rowwise() %>%
    mutate(asc = all(diff(c_across(cols = everything())>=0))) %>% 
    filter(asc==TRUE) %>% tally

这也很慢,但不占用内存。

 9 %>% 
  rerun(1:6) %>% crossing(!!!.,.name_repair = "minimal")  %>% 
  set_names(glue::glue('c{1:ncol(.)}')) %>% 
  filter(pmap_lgl(.,~{
    if(all(list(...) %>% flatten_dbl() %>% diff() >=0)) return(TRUE) else return(FALSE)
  })) %>% tally

这是一个 tidyverse 方法,它依赖于 purrr:

expand.grid(replicate(9, 1:6, FALSE)) %>%
  filter(reduce(map2(.[, -length(.)], .[, -1], ~ .x <= .y), `&`)) %>%
  tally()

这在管道环境中有些困难。我们都需要比较列 nn + 1,同时将 done 缩减为逻辑向量。然后我们需要对原始数据集进行过滤。

如果您对计数感兴趣,我们可以对逻辑向量求和。

expand.grid(replicate(9, 1:6, FALSE)) %>%
  {sum(reduce(map2(.[, -length(.)], .[, -1], ~ .x <= .y), `&`))}

最后,如果您不介意多一个依赖项, 可以使用您的一种方法与您正在做的事情并行:

library(matrixStats)

expand.grid(replicate(9, 1:6, FALSE)) %>%
  {sum(rowAlls(rowDiffs(as.matrix(.)) >= 0L))}