Funcţia alloc_by_class()
din [1] avea o idee care nu-i rea: alocă pe zile – prin funcţia days2rnd()
– orele clasei curente din lista de clase primită ca argument; dacă alocarea făcută nu îndeplineşte anumite condiţii, atunci permută aleatoriu profesorii clasei şi reia alocarea; dacă reapelând astfel days2rnd()
pentru clasa curentă, rezultă eroarea de depăşire a capacităţii stivei de apeluri – atunci (prin tryCatch()
) se permută aleatoriu clasele din lista iniţială şi se re-apelează alloc_by_class()
(în noua ordine a claselor…):
alloc_by_class <- function(vCls) { # Clasele ale căror ore trebuie alocate pe zile days2rnd <- function(Q) { # 'Q' conţine liniile din FRM cu o aceeaşi 'cls' # Sau returnează alocarea pe zile a orelor clasei (îndeplinind anumite condiţii) # Sau permută profesorii şi se re-apelează, încercând o altă alocare } tryCatch( # blocul "principal" al funcţiei alloc_by_class() { FRM %>% # încadrarea pe clase a profesorilor, oră de oră filter(cls %in% vCls) %>% split(., .$cls) %>% map_df(., function(K) days2rnd(K)) }, error = function(err) { tryCatch( alloc_by_class(sample(vCls)), # permută clasele şi reapelează error = function(e) NULL ) } ) # Returnează distribuţia pe zile a orelor claselor indicate }
Avem aici o greşală de programare, chiar nostimă; dar adevărata greşală constă în faptul că n-am testat separat, conţinutul blocului „principal” – următoarea imitare separată ar fi lămurit lucrurile:
exTest <- function() { vCls <- sample(Cls) # permută aleatoriu clasele print(vCls) scl <- FRM %>% filter(cls %in% vCls) %>% split(., .$cls) %>% map(., function(K) K$cls[1]) # lista claselor scl <- do.call(c, scl) names(scl) <- NULL print(scl) } # rezultă aceeaşi ordine a claselor, indiferent de permutarea făcută!
La fiecare invocare extest()
, în vCls
avem o nouă permutare a claselor, dar în final clasele sunt afişate într-o aceeaşi ordine: filter()
produce subsetul de rânduri corespunzător claselor indicate, dar în aceeaşi ordine a rândurilor ca în FRM
, iar split()
separă pe clase rândurile respective, dar în ordinea existentă iniţial (nu în ordinea existentă după permutarea făcută asupra claselor).
Nu elementele vectorului de clase trebuie permutate, ci grupurile din lista rezultată prin split()
:
exTest1 <- function() { scl <- FRM %>% filter(cls %in% Cls) %>% # numai pentru clasele indicate split(., .$cls) %>% # separă pe clase sample(.) %>% # permută grupurile asociate claselor map(., function(K) K$cls[1]) # clasele, în urma permutării print(scl) }
Este de tot hazul, că am observat greşala abia după ce am rulat câteva ore în şir alloc_by_class()
, obţinând cele 1455 de distribuţii vizate în [1]… Este probabil şi mai de haz, faptul că mi-am dat seama de greşală oarecum întâmplător – luând aminte la ce zice help(filter)
: "Rows are a subset of the input, but appear in the same order.". Se verifică astfel, încă o dată, că cel mai bun obicei al unui programator (din afara sferei comerciale, probabil) este acela de a (re)citi şi a rescrie lucrurile de care se ocupă.
vezi Cărţile mele (de programare)