在R或SQL中进行分段

时间:2015-07-16 18:00:18

标签: sql sql-server r oracle bucket-sort

我对问题完全感到困惑,并希望得到一些指导。我从1到8的集合中挑选8个数字的随机集合(例如,5,6,8,1,3,4,2,7)并尝试根据顺序将这些数字作为连续数字的子集他们出现了。

对于上面的示例,第一个桶将以5开头,然后将添加6。点击8时,将启动一个新的桶。每当我们找到属于现有存储桶的数字时(例如,当我们到达2时,它就可以添加到1的存储桶中),我们将其添加到那里。在这个例子中,在我们到达的所有8个数字之后:

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

共有4个水桶。

我实际上并不关心桶的内容,我只想计算给定的8位数字随机数的桶数。我计划循环遍历这些8位数序列中的1000个。

6 个答案:

答案 0 :(得分:5)

如果您只对桶数感兴趣,

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

并且,在函数中更简洁

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

并且,这是一个获取存储桶内容的递归实现。

new

答案 1 :(得分:5)

我的解决方案,不是从nongkrong扯下来的,而是非常相似的。你得到了桶的数量:

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

我相信可以对其进行矢量化,然后它可以完美地缩放。

答案 2 :(得分:4)

受@jangorecki的启发但更快:

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

答案 3 :(得分:3)

这是一个矢量化答案:

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))

请注意,我们只需要声明ind.mat一次,因此可以很好地扩展到复制。

答案 4 :(得分:2)

我对R不是很熟悉,但你肯定可以这样做:

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

编辑:

您可以执行以下操作:

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 )
}

答案 5 :(得分:2)

我不确定它在Oracle上的表现如何,但由于您已经添加了SQL Server标记,因此这是一个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;

它背后的想法是计算下一个数字在当前数字之前的情况,开始一个新的桶而不是继续当前的数据。这里唯一的问题是边界,所以我添加了尾随零。没有它,最少设置项(在你的情况下为1)不算作单独的桶。

P.S。 dbo.Sequencer是一个递增整数的表。我通常会在数据库中保留一个以投射有序序列。