将样本转换为索引


12

我们将球放入固定数量垃圾箱中。这些垃圾箱开始为空。

Empty bin (a=4): 0 0 0 0 

然后我们一一将球加到垃圾箱中。

0 0 0 1  or
0 0 1 0  or
0 1 0 0  or
1 0 0 0

我们需要一种快速的方法来循环遍历垃圾箱的所有可能状态,没有重复且没有任何遗漏,并且我们不想列举所有可能的垃圾箱。因此,我们改为为每个bin配置分配一个索引。

我们通过以特定方式对可能的配置进行排序来分配索引:

  1. 按总和升序排序:因此,首先0 0 0 0添加可能的配置,然后添加1个球,然后添加2个,依此类推。
  2. 然后,从第一个容器到最后一个容器,以升序对每个和进行排序:

    0 0 0 2
    0 0 1 1
    0 0 2 0 
    0 1 0 1
    0 1 1 0 
    0 2 0 0 
    etc
    
  3. 然后,该索引通过此列表升序分配:

    0 0 0 0  -> 1
    0 0 0 1  -> 2
    0 0 1 0  -> 3
    0 1 0 0  -> 4
    1 0 0 0  -> 5
    0 0 0 2  -> 6
    0 0 1 1  -> 7
    0 0 2 0  -> 8
    0 1 0 1  -> 9
    0 1 1 0  -> 10
    0 2 0 0  -> 11 
    

规则

创建一个函数或程序,该函数或程序采用具有非负整数的任意大小的列表,并打印或输出其索引。您可以假设a至少为2。最短的代码获胜。您可以使用0索引输出或1索引输出,但是请指定要使用的输出。注意:此处所有示例均采用1索引。

范例程式码

在R中没有打高尔夫球:

nodetoindex <- function(node){
  a <- length(node)
  t <- sum(node)
  if(t == 0) return(1)

  index <- choose(t-1 + a, a)

  while(sum(node) != 0){
    x <- node[1]
    sumrest <- sum(node)
    if(x == 0){
      node <- node[-1]
      next
    }
    a <- length(node[-1])
    index <- index + choose(sumrest + a, a) - choose(sumrest - x + a, a)
    node <- node[-1]
  }
  return(index + 1)
} 

测试用例

10 10 10 10 -> 130571
3 1 4 1 5 9 -> 424407
2 9 -> 69
0 0 0 -> 1
0 0 1 -> 2
0 0 0 0 0 0 -> 1
1 0 0 0 0 1 -> 23

当计数具有不同数字位数时,如何通过串联的数值进行排序?
TheBikingViking

@TheBikingViking嗯,没想到,我更改了措辞以反映示例代码和测试用例。在每个总和内,配置首先在第一个容器中排序,然后在第二个容器中排序,依此类推。
2016年

Answers:


3

果冻,8字节

S0rṗLSÞi

在线尝试!

蛮力解决方案。对于TIO来说,第一个测试用例太多了,但是我已经在笔记本电脑上本地验证了。第二个测试用例需要太多RAM,即使对于我的台式机也是如此。

怎么运行的

S0rṗLSÞi  Main link. Argument: A (array)

S         Compute the sum s of A.
 0r       Create the range [0, ..., s].
    L     Yield the length l of A.
   ṗ      Cartesian power; yield the array of all l-tuples over [0, ..., s], in
          lexicographical order.
     SÞ   Sort the l-tuples by their sums. The sorting mechanism is stable, so
          l-tuples with the same sum are still ordered lexicographically.
       i  Find the index of A in the generated array of tuples.

真好 您对RAM的评论使我想起了这一挑战的根源。对于我的论文,我需要遍历所有可能的数组,使a = 8,并尽可能高。将数组转换为索引并对其进行循环的想法完全来自RAM的限制:P
JAD

这也是示例代码如此冗长的原因:P
JAD 2016年

1

Clojure,152个字节

#(loop[v[(vec(repeat(count %)0))]i 1](if-let[r((zipmap v(range))%)](+ r i)(recur(sort(set(for[v v i(range(count v))](update v i inc))))(+ i(count v)))))

没有我想的那么容易。少打高尔夫球的版本:

(def f (fn[t](loop[v[(vec(repeat(count t)0))]i 1]
               (if-let[r((zipmap v(range))t)](+ r i)
                 (recur (sort-by (fn[v][(apply + v)v]) (set(for[v v i(range(count v))](update v i inc))))
                        (+ i(count v)))))))

循环遍历当前状态v,从到元素的v排名创建一个哈希映射,如果找到了搜索到的状态,则返回其排名(+先前看到的状态的数量)。如果未找到,则以一组新的可能状态递归。

哦,实际上,我们不需要该自定义排序功能,因为每个循环中的所有状态都具有相同的总和。这并不像我预期的那样慢,[3 1 4 1 5 9]只花了2.6秒。


1

Mathematica,50个字节

的端口丹尼斯的果冻答案

0~Range~Tr@#~Tuples~Length@#~SortBy~Tr~Position~#&

未命名函数,将整数列表作为输入,并返回一个深度为2的列表,其中单个整数作为输出;例如,最后一个测试用例的输入为{1,0,0,0,0,1},输出为{{23}}

一个略微偏离版本的版本是:

Position[SortBy[Tuples[Range[0,Tr[#]],Length[#]],Tr],#]&

通常,我们可以使用前缀表示法(function@n代替function[n])和中缀表示法(a~function~b代替function[a,b])在Mathematica中保存单个字节。但是,只有当生成的代码恰好与Mathematica的内在优先顺序应用函数时,这才起作用。在这里,我感到非常惊讶,因为它具有六组方括号,实际上可以删除所有方括号,并使用提交的代码(令人愉悦的无括号)节省了六个字节。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.