2015-07-16 15 views
6

Sono completamente perplesso su un problema e vorrei qualche consiglio. Raccolgo set casuali di 8 numeri dal set da 1 a 8 (ad esempio, 5,6,8,1,3,4,2,7) e proviamo a utilizzare questi numeri come sottoinsiemi di numeri sequenziali in base all'ordine Sembrano.Bucketing in R o SQL

Per l'esempio precedente, il primo segmento inizierà con un 5, quindi il 6 verrà aggiunto. Al raggiungimento dell'8 un nuovo secchio sarebbe stato avviato. Ogni volta che arriviamo a un numero che appartiene a un bucket esistente (ad esempio, quando raggiungiamo 2, può essere aggiunto al bucket 1), lo aggiungiamo lì. In questo esempio, dopo tutti gli 8 numeri arriveremo a:

5,6,7 
8 
1,2 
3,4 

Per un totale di 4 benne.

Non sono realmente interessato al contenuto dei bucket, voglio solo contare quanti bucket ci sono per un dato insieme casuale di 8 cifre. Ho in programma di eseguire il looping di un set di 1000 di queste sequenze a 8 cifre.

+2

Non capisco la logica dietro questo. 7 non è apparso nella prima sequenza. Né 2 nel terzo. –

+1

Quindi l'idea è che stiamo attraversando cifre per cifra, creando un nuovo bucket se un numero non è in sequenza quando un bucket precedente. Quindi 5 crea il primo, 6 va in esso. 8 Crea il secondo secchio. 1 crea il terzo. 3 crea il 4 °. Quindi 4,2 e 7 vengono aggiunti ai bucket già esistenti (perché sono in sequenza). Strano problema, sì, ma un po 'interessante. –

+2

Così tipo di creazione di pile di solitari ... – MichaelChirico

risposta

2

Io non sono troppo familiarità con R, ma si può sicuramente fare qualcosa di simile:

setOf8 = your array of 8 numbers 
buckets=0 
for(i = [2,8]) 
{ 
    if((setOf8[i] < setOf8[i-1])) 
    { 
     buckets = buckets + 1 
    } 
} 

EDIT:

Si potrebbe fare qualcosa di simile:

func countBuckets(buckets, set) 
{ 
    set = your array 
    current = 1 
    for(i = [2,size(set)]) 
    { 
     if(set[current] + 1 == set[i]) 
     { 
      set.remove(current) 
      current = set[i-1] 
     } 
    } 
    if(size(set) == 0) 
    { 
     return buckets 
    } 
return countBuckets(buckets + 1, set) 
} 
+0

Grazie. Ho iniziato con qualcosa del genere, ma il problema si verifica con numeri come quello degli ultimi 7, non è in sequenza, ma non inizia un nuovo bucket. Deve essere aggiunto al primo bucket. –

+0

Sto male con la formattazione, vedi post modificato. – Brian

5

Se sei interessato al numero di benne,

## Your data 
dat <- c(5,6,8,1,3,4,2,7) 

## Get the number of buckets 
count <- 0 
for (i in seq_along(dat)) 
    if (!((dat[i] - 1) %in% dat[1:i])) count <- count+1 
count 
# 4 

e, più succintamente in una funzione

countBuckets <- function(lst) sum(sapply(1:length(lst), function(i) 
    (!((lst[i]-1) %in% lst[1:i])))) 

Ed, ecco un implementazione ricorsiva per ottenere il contenuto di benne.

f <- function(lst, acc=NULL) { 
    if (length(lst) == 0) return(acc) 
    if (missing(acc)) return(Recall(lst[-1], list(lst[1]))) 

    diffs <- sapply(acc, function(x) lst[1] - x[length(x)] == 1) 
    if (any(diffs)) { 
     acc[[which(diffs)]] <- c(acc[[which(diffs)]], lst[1]) 
    } else { acc <- c(acc, lst[1]) } 
    return (Recall(lst[-1], acc)) 
} 

f(dat) 

# [[1]] 
# [1] 5 6 7 
# 
# [[2]] 
# [1] 8 
# 
# [[3]] 
# [1] 1 2 
# 
# [[4]] 
# [1] 3 4 
+2

Questa risposta non sta ottenendo il suo apprezzamento meritato –

2

io non sono sicuro di come se la passeranno su Oracle, ma dal momento che si è aggiunto il tag di SQL Server, ecco una soluzione T-SQL:

declare @set char(8) = '56813427'; 

with cte as (
    select s.Id, cast(substring(@set, s.Id, 1) as int) as [Item] 
    from dbo.Sequencer s 
    where s.Id between 1 and 8 
    union all 
    select 9 as [Id], 0 as [Item] 
) 
select count(*) as [TotalBuckets] 
from cte s 
    inner join cte n on (s.Item = n.Item - 1) and s.Id > n.Id; 

L'idea alla base è quella di conta i casi in cui il prossimo numero va prima di quello corrente, iniziando un nuovo bucket invece di continuare quello attuale. L'unico problema qui è con i limiti, quindi ho aggiunto zero finale. Senza di esso, l'elemento minimo impostato (1 nel tuo caso) non viene conteggiato come un bucket separato.

P.S. dbo.Sequencer è una tabella con numeri interi incrementali. Di solito ne tengo uno nel database per proiettare sequenze ordinate.

5

La mia soluzione, non strappata da nongkrong ma abbastanza simile. È possibile ottenere il conteggio dei secchi:

x <- as.integer(c(5,6,8,1,3,4,2,7)) 
sum(is.na(sapply(1:length(x), function(i) which((x[i]-1L)==x[1:i])[1L]))) 
# [1] 4 

credo sia possibile vectorize esso, allora sarebbe in scala perfettamente.

+0

appena eseguito su 1000 repliche, è già PDQ – MichaelChirico

4

Ispirato @jangorecki ma più veloce:

x <- sample(8L) 
1 + sum(sapply(2L:8L, function(i) !any(x[i] - x[1:(i - 1L)] == 1))) 
3

Ecco una risposta vectorized:

ind.mat <- matrix(rep(1:8, each=8), ncol=8) 
ind.mat[upper.tri(ind.mat)] <- NA 
8 - sum(rowSums(matrix(rep(x, 8), ncol=8) - x[ind.mat] == 1, na.rm=TRUE)) 

Nota che abbiamo solo bisogno di dichiarare ind.mat una volta, in modo scalare fino bene alla replica.

+1

Inoltre dovrebbe ottenere una maggiore velocità se OP è in grado di fornire tutti i 1000 casi e creare una matrice singola su di essi. Nell'implementazione più pessimistica l'id del caso formerebbe una dimensione aggiuntiva nell'array. – jangorecki