FIFO缓存未命中数


35

这个挑战真的很简单(并且是更困难挑战的先兆!)。

给定一个资源访问数组(用非负整数简单表示)和一个参数n,返回假定我们的缓存具有容量n并在充满时使用先进先出(FIFO)弹出方案的缓存未命中数。

例:

4, [0, 1, 2, 3, 0, 1, 2, 3, 4, 0, 0, 1, 2, 3]
0 = not in cache (miss), insert, cache is now [0]
1 = not in cache (miss), insert, cache is now [0, 1]
2 = not in cache (miss), insert, cache is now [0, 1, 2]
3 = not in cache (miss), insert, cache is now [0, 1, 2, 3]
0 = in cache (hit), cache unchanged
1 = in cache (hit), cache unchanged
2 = in cache (hit), cache unchanged
3 = in cache (hit), cache unchanged
4 = not in cache (miss), insert and eject oldest, cache is now [1, 2, 3, 4]
0 = not in cache (miss), insert and eject oldest, cache is now [2, 3, 4, 0]
0 = in cache (hit), cache unchanged
1 = not in cache (miss), insert and eject oldest, cache is now [3, 4, 0, 1]
2 = not in cache (miss), insert and eject oldest, cache is now [4, 0, 1, 2]
3 = not in cache (miss), insert and eject oldest, cache is now [0, 1, 2, 3]

因此,在此示例中,有9个未中。也许代码示例有助于更好地解释它。在Python中:

def num_misses(n, arr):
    misses = 0
    cache = []
    for access in arr:
        if access not in cache:
            misses += 1
            cache.append(access)
            if len(cache) > n:
                cache.pop(0)
    return misses

其他一些测试用例(其中包含对下一个挑战的提示-注意到任何好奇的地方吗?):

0, [] -> 0
0, [1, 2, 3, 4, 1, 2, 3, 4] -> 8
2, [0, 0, 0, 0, 0, 0, 0] -> 1
3, [3, 2, 1, 0, 3, 2, 4, 3, 2, 1, 0, 4] -> 9
4, [3, 2, 1, 0, 3, 2, 4, 3, 2, 1, 0, 4] -> 10

以字节为单位的最短代码获胜。


15
我已经看了notice anything curious?一段时间,只是注意到了,增加缓存容量并不一定减少未命中次数?!
JungHwan Min

@JungHwanMin正确!实际上,它变得更糟的程度是无限的。
orlp

我们可以用一元输出数字吗?
dylnan '18

9
被称为贝拉迪异常和先进先出的就是典型的例子。异常是无限的
virtualirfan

@dylnan不,对不起。
orlp

Answers:


11

JavaScript(ES6),55个字节

方法#1:缓存覆盖输入

以currying语法接受输入(cache_size)(list)

n=>a=>a.map(x=>a[a.indexOf(x,k>n&&k-n)<k||k++]=x,k=0)|k

在线尝试!

怎么样?

我们使用初始化为0的单独指针k用缓存覆盖输入数组a []

我们a.indexOf(x, k > n && k - n) < k用来测试x是否在缓存中。

缓存的增长速度不会超过遍历原始数组的速度,因此可以保证在缓存窗口之内或之外都能找到每个值(即indexOf()永远不会返回-1)。

如果在max(0,k-n)k-1(包括边界)之间的索引处找到一个值,则该值在高速缓存中,在这种情况下,我们执行a [true] = x。这只会影响a []之后的基础对象的属性,而不会更改数组 a []。否则,我们做a [k ++] = x

以下是[1, 1, 2, 3, 3, 2, 1, 4]缓存大小为2的输入的不同步骤:

  • 粗体边框:map()指针
  • 括号:缓存指针k
  • 橙色:当前缓存窗口
  • 黄色:过期的缓存值

方法1


JavaScript(ES6),57个字节

方法2:将缓存附加到输入的末尾

以currying语法接受输入(cache_size)(list)

n=>a=>a.map(x=>n*~a.indexOf(~x,-n)||a.push(~x)&k++,k=0)|k

在线尝试!

怎么样?

因为输入数组一个[]保证包含非负整数,我们可以安全地追加所述高速缓存处的端部一个[]通过使用一个补〜X的每个值的X

我们使用n * ~a.indexOf(~x, -n)测试是否〜X是最后中发现ñ值。每当此测试失败,我们追加〜X一个[]并递增未命中的数目ķ

下面是使用此方法的上述示例的不同步骤。因为仅将高速缓存值附加在数组的末尾,所以没有显式的高速缓存指针。

方法#2



9

Python 2,58字节

lambda n,a:len(reduce(lambda c,i:[i][i in c[:n]:]+c,a,[]))

在线尝试!

感谢ovs提供3个字节,xnor提供3个字节。


您应该可以通过将set放在后面来节省字节c+=,因为出于某种原因它会为您转换为列表。
xnor

(啊,是的,c+={i}-set(c[-n:])对肯定的n行之有效。但是妮米指出,这样做c[-n:]是不对的n == 0,所以我不能使用+=,因此这个窍门-太糟糕了。)
林恩(Lynn

1
@林恩啊,我明白了。reduce仍保存字节:lambda n,a:len(reduce(lambda c,i:[i][i in c[:n]:]+c,a,[]))
xnor

7

R69 64 62字节

function(n,A,K={}){for(i in A)K=c(i[!i%in%K[0:n]],K);sum(K|1)}

在线尝试!

感谢JayCe提出了一些改进建议,并感谢DigEmAll给另外两对夫妇!


我想+前面的Ff(0,{})要返回0?
JayCe

@JayCe是的,这是经典的高尔夫运动,同时具有F预初始化的返回值。
朱塞佩

1
小的进步。另外,如果接受一元输出,则可以节省一些字节。
JayCe

@JayCe发现了更多字节!
朱塞佩

1
@JDL是的,对此感到遗憾,q但这仍然是一个好主意!使用NA不如使用好,{}因为我实际上关心这里的长度(而且我实际上并不是从缓存中弹出元素)。
朱塞佩

5

Haskell,61 58字节

n!a|let(a:b)#c|elem a c=b#c|1<2=1+b#take n(a:c);_#_=0=a#[]

在线尝试!

n!a|      =a#[]     -- take input 'n' and a list 'a'
                    -- and call # with the initial list and an empty cache
 let                -- bind function '#':
  (a:b)#c           -- if there's at least one element 'a' left in the list
     |elem a c=b#c  --  and it's in the cache, go on with the same cache
                    --  and the remainder of the list
     |1<2=          -- else (i.e. cache miss)
          1+        --  add one to the recursive call of
       b#           --  the remainder of the list and 
       take n(a:c)  --  the first n elements of 'a' prepended to the cach
 _#_=0              -- if there's no element in the list, return 0

编辑:-3字节感谢@Lynn。


5

05AB1E17 16字节

)svDyå_i¼y¸ìI£]¾

在线尝试!

说明

)                   # wrap the stack in a list
 sv                 # for each item y in input list
   D                # duplicate current list
    yå_i            # if y is not contained in the current list
        ¼           # increment counter
         y¸ì        # prepend y to the current list
            I£      # keep the first input elements
              ]¾    # end loop and push counter

@nimi:谢谢!已固定,但保存了一个字节:)
Emigna

5

Kotlin82 69字节

{a,n->a.fold(List(0){0}){c,v->if(v!in c.takeLast(n))c+v else c}.size}

将输入作为IntArray而不是典型值List<Int>(这应该不是问题。)这使用了“构建缓存历史记录并计算其长度”的方法。

在线尝试!

说明

{ a, n ->                         // lambda where a is accesses and n is cache size
    a.fold(List(0){0}) { c, v ->  // fold on empty list
        if(v !in c.takeLast(n))   // if resource is not in last n cache inserts
            c + v                 // insert to cache list
        else
            c                     // return cache as is
    }.size                        // length of cache list is number of inserts
}

创建一个空列表

Kotlin没有集合文字,但是它确实具有创建新集合的功能。

创建空的正确方法List<Int>很简单:

List<Int>()

但是如果我们滥用大小和初始值设定项args来执行此操作,则会更短:

List(0){0}
List(0)       // List of size 0
       { 0 }  // with generator returning 0

由于生成器lambda返回0,因此Kotlin将该列表的类型推断为List<Int>,大小为0表示此列表为空。


4

Perl 6,48个字节

{my@c;$_@c.tail($^n)||push @c,$_ for @^o;+@c}

测试一下

{  # bare block with placeholder params $n,@o

  my @c; # cache


      $_  @c.tail($^n) # is the current value in the last bit of the cache
    ||
      push @c, $_       # if not add it to the cache

  for                   # do this for all of

    @^o;                # the input array


  +@c                   # numify the cache (the count)
}

4

Java 8,96字节

咖喱味lambda,采用缓存大小(int)和访问列表(可变java.util.List<Integer>)并返回int

s->a->{int w=0,m=0,i;for(int r:a)m+=(i=a.indexOf(r))<w&i<s?0:s<1?1:1+0*a.set(w++%s,r);return m;}

在线试用

不打高尔夫球

这会将s输入列表中的第一个(最多)插槽用于高速缓存。

s ->
    a -> {
        int
            w = 0,
            m = 0,
            i
        ;
        for (int r : a)
            m +=
                (i = a.indexOf(r)) < w & i < s ?
                    0
                    s < 1 ?
                        1
                        : 1 + 0*a.set(w++ % s, r)
            ;
        return m;
    }

致谢

  • 错误修复感谢妮米

4

Pyth 16 15 18 14  13字节

感谢isaacg,节省了1个字节。

luaW-H>QGGHEY

测试套件!

这个挑战非常适合Pyth的u结构。

怎么运行的

luaW-H>QGGHEY     Full program. Q = the cache length, E = the list.
 u         E      Reduce E with G = current value and H = corresponding element
            Y     With starting value Y, which is preinitialised to [] (empty list).
   W              Conditional application. If...
    -H            ... Filtering H on absence of...
      >QG         ... The last Q elements of G... 
                  ... Yields a truthy value (that is, H is not in G[-Q:]), then...
  a      GH       ... Append H to G.
                  ... Otherwise, return G unchanged (do not append H at all).
l                  Get the length of the result.

aW-H>QGGH击败?}H<GQG+HG1
isaacg

@isaacg谢谢!最初我有+G*]H!}H>QG,但是当我打高尔夫球时,我真的没有想到W……不错!
Xcoder先生18年

到底是u做什么的?
dylnan

@dylnan u是带有初始值运算符的reduce。就像果冻ƒ
Xcoder先生,2018年


2

Japt,16个字节

;£A¯V øX ªAiXÃAl

试试吧


说明

                     :Implicit input of array U and integer V
 £                   :Map over each X in U
; A                  :  Initially the empty array
   ¯V                :  Slice to the Vth element
      øX             :  Contains X?
         ª           :  Logical OR
          AiX        :  Prepend X to A
             Ã       :End map
              Al     :Length of A

1

K442 40个字节

解:

{*1+/1_{r,,(y;x#z,y)r:~z in y:*|y}[x]\y}

例子:

q)k)f:{*1+/1_{r,,(y;x#z,y)r:~z in y:*|y}[x]\y}
q)f[0;1 2 3 4 1 2 3 4]
8
q)f[2;0 0 0 0 0 0 0]
1
q)f[3;3 2 1 0 3 2 4 3 2 1 0 4]
9
q)f[4;3 2 1 0 3 2 4 3 2 1 0 4]
10

说明:

对于内部函数,y是缓存,z是请求,x是缓存大小。

{*1+/1_{r,,(y;x#z,y)r:~z in y:*|y}[x]\y} / the solution
{                                      } / lambda taking 2 args
       {                         }       / lambda taking 3 args
                                  [x]\y  / iterate over lambda with each y
                              *|y        / last (reverse, first) y
                            y:           / assign to y
                       z in              / is z in y?
                      ~                  / not 
                    r:                   / assign result to r (true=1,false=0)
           ( ;     )                     / 2-element list
                z,y                      / join request to cache
              x#                         / take x from cache (limit size)
            y                            / (else) return cache unchanged
          ,                              / enlist this result
        r,                               / join with r
     1_                                  / drop the first result
  1+/                                    / sum up (starting from 1)
 *                                       / take the first result

笔记:

可能有更好的方法来完成所有这些操作,但这是我想到的第一种方法。

该函数可以像这样运行36个字节

q)k)*1+/1_{r,,(y;x#z,y)r:~z in y:*|y}[4]\3 2 1 0 3 2 4 3 2 1 0 4
10

备选方案-使用全局变量存储状态(不是很像K),为42个字节

{m::0;(){$[z in y;y;[m+:1;x#z,y]]}[x]\y;m}

1

Brain-Flak,172字节

(([{}]<>)<{({}(()))}{}>)<>([]){{}<>((({})<{({}()<<>(({})<({}<>({}<>))>)<>>)}{}>)<<>(({})([{}]<>{<>(){[()](<{}>)}{}<><({}()<<>({}<>)>)>}{})){(<{}{}>)}{}>)<>([])}{}<>({}[]<>)

在线尝试!

# Initialize cache with n -1s (represented as 1s)
(([{}]<>)<{({}(()))}{}>)<>

# For each number in input
([]){{}

    # Keep n on third stack
    <>((({})<

        # For last n cache entries, compute difference between entry and new value
        {({}()<<>(({})<({}<>({}<>))>)<>>)}{}

    >)<

        # Get negation of current entry and...
        <>(({})([{}]<>

            {

                # Count cache hits (total will be 1 or 0)
                <>(){[()](<{}>)}{}

                # while moving entries back to right stack
                <><({}()<<>({}<>)>)>

            }{}

        ))

        # If cache hit, don't add to cache
        {(<{}{}>)}{}

    >)

<>([])}{}

# Compute cache history length minus cache size (to account for the initial -1s)
<>({}[]<>)

1

果冻,18字节

Ṗɼṛ;ɼe®Uḣ⁴¤C$¡€ṛLɼ

在线尝试!

将列表作为第一个参数,并将缓存容量作为第二个参数。

Ṗɼṛ;ɼe®Uḣ⁴¤C$¡€ṛLɼ
 ɼ                 Apply to the register:
Ṗ                  Pop. This initializes the register to the empty list.
  ṛ                Right argument. Yields the list of addresses.
              €    For each element in the list
             ¡     If{
     e                 the element is in
          ¤            nilad{
      ®                      the register
       U                     reversed
        ḣ                    first...
         ⁴                   (cache depth) number of elements
                             }
           C           Complement. 1 <-> 0. Easier to type this than "not".
            $          Combines everything up to `e` into a monad
                      }
                    Then{
    ɼ                    Apply to the register and store the result
   ;                     Append the element
                        }
                ṛ   Right argument:
                  ɼ Apply to the register:
                 L  Length

1

红宝石43 40字节

->s,a,*r{a.count{|*x|r!=r=(r|x).pop(s)}}

在线尝试!

感谢histocrat削减了3个字节。


1
好答案!您可以通过将r初始化为参数列表的一部分来节省几个字节:->s,a,*r这还提供了额外的功能,即调用方可以通过传递额外的参数来初始化缓存:)
histocrat

哦,并且类似地将其x转换为数组:.count{|*x|
历史学家

1

C(GCC) 112 110 108个字节

f(x,y,z)int*y;{int*i=y+z,b[x],m=0;for(wmemset(b,z=-1,x);i-y;y++)wmemchr(b,*y,x)?:++m*x?b[z=++z%x]=*y:0;x=m;}

在线尝试!

少打高尔夫球

f(x,y,z)int*y;{
 int*i=y+z,b[x],m=0;
 for(wmemset(b,z=-1,x);i-y;y++)
  wmemchr(b,*y,x)?:
   ++m*
   x?
    b[z=++z%x]=*y
   :
    0;
 x=m;
}

0

C(gcc),156字节

s,n,m,i,j;f(x,_)int*_;{int c[x];n=m=0;for(i=0;i<x;++i)c[i]=-1;for(i=s=0;_[i]>=0;++i,s=0){for(j=0;j<x;++j)s|=(c[j]==_[i]);if(!s){c[n++]=_[i];m++;n%=x;}}x=m;}

在线尝试!

描述:

s,n,m,i,j;                       // Variable declaration
f(x,_)int*_;{                    // F takes X (the cache size) and _ (-1-terminated data)
    int c[x];                    // declare the cache
    n=m=0;                       // next queue insert pos = 0, misses = 0
    for(i=0;i<x;++i)c[i]=-1;     // initialize the cache to -1 (invalid data)
    for(i=s=0;_[i]>=0;++i,s=0){  // for each datum in _ (resetting s to 0 each time)
        for(j=0;j<x;++j)         // for each datum in cache
            s|=(c[j]==_[i]);     // set s if item found
        if(!s){                  // if no item found
            c[n++]=_[i];         // add it to the cache at position n
            m++;                 // add a mis
            n%=x;                // move to next n position (with n++)
        }} x=m;}                 // 'return' m by assigning to first argument

建议wmemset(c,-1,x)代替n=m=0;for(i=0;i<x;++i)c[i]=-1n=m=i=s=0代替i=s=0for(j=x;j--;)代替for(j=0;j<x;++j),和s||(c[n++]=_[i],m++,n%=x);代替if(!s){c[n++]=_[i];m++;n%=x;}
ceilingcat



0

,129字节

|l:&[_],s|if s>0{let(mut c,mut m)=(vec![-1;s],0);for n in l.iter(){if!c.contains(n){c.remove(0);c.push(*n);m+=1;}}m}else{l.len()}

在线尝试!

不打高尔夫球

|l: &[isize], s: usize| {
    if s > 0 {
        let mut c = vec![-1; s];
        let mut m = 0;
        for n in l.iter() {
            if !c.contains(n) {
                c.remove(0);
                c.push(*n);
                m += 1;
            }
        }
        m
    } else {
        l.len()
    }
}

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.