Número de falhas no cache FIFO

35

Esse desafio é realmente simples (e precursor de um mais difícil!).

Dada uma variedade de acessos a recursos (simplesmente indicados por números inteiros não negativos) e um parâmetro n, retorne o número de erros de cache que eles teriam, assumindo que nosso cache tenha capacidade ne usando um esquema de ejeção de FIFO quando estiver cheio .

Exemplo:

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]

Portanto, neste exemplo, houve 9 erros. Talvez um exemplo de código ajude a explicar melhor. Em 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

Alguns outros casos de teste (que contêm uma dica para o próximo desafio - notam algo curioso?):

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

O menor código em bytes vence.

orlp
fonte
15
Eu estava olhando a última declaração notice anything curious?por um tempo agora ... e apenas notei que aumentar a capacidade do cache não necessariamente diminui o número de erros ?!
JungHwan
@JungHwanMin Correct! De fato, o quanto isso pode piorar é ilimitado.
orlp
Podemos emitir o número em unário?
dylnan
9
Conhecida como anomalia de Bélády e FIFO é o exemplo clássico. A anomalia é ilimitada .
Virtualirfan
@dylnan Não, desculpe.
orlp

Respostas:

11

JavaScript (ES6), 55 bytes

Método # 1: o cache substitui a entrada

Recebe entrada na sintaxe de currying (cache_size)(list).

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

Experimente online!

Quão?

Sobrescrevemos a matriz de entrada a [] com o cache, usando um ponteiro separado k inicializado em 0 .

Usamos a.indexOf(x, k > n && k - n) < kpara testar se x está no cache.

O cache não pode crescer mais rápido do que a matriz original é percorrida; portanto, é garantido que cada valor seja encontrado, dentro ou fora da janela do cache (ou seja indexOf(), nunca retornará -1 ).

Um valor está no cache se for encontrado em um índice entre max (0, k - n) e k - 1 (ambos os limites incluídos); nesse caso, fazemos um [verdadeiro] = x . Isso afeta apenas uma propriedade do objeto subjacente atrás de um [], mas não altera a matriz a [] . Caso contrário, fazemos um [k ++] = x .

Exemplo

Abaixo estão as diferentes etapas da entrada [1, 1, 2, 3, 3, 2, 1, 4]com um tamanho de cache 2 :

  • bordas em negrito: ponteiro map ()
  • colchetes: ponteiro de cache k
  • laranja: janela de cache atual
  • amarelo: valores de cache expirados

Método 1


JavaScript (ES6), 57 bytes

Método # 2: o cache é anexado no final da entrada

Recebe entrada na sintaxe de currying (cache_size)(list).

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

Experimente online!

Quão?

Como a matriz de entrada a [] tem garantia de conter números inteiros não negativos, podemos anexar com segurança o cache no final de [] usando o complemento de um ~ x de cada valor x .

Usamos n * ~a.indexOf(~x, -n)para testar se ~ x é encontrado entre os últimos n valores. Sempre que esse teste falha, anexamos ~ x a [] e incrementamos o número de erros k .

Exemplo

Abaixo estão as diferentes etapas para o mesmo exemplo acima, usando este método. Como os valores do cache são simplesmente anexados no final da matriz, não há ponteiro explícito do cache.

método # 2

Arnauld
fonte
9

Python 2 , 58 bytes

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

Experimente online!

Graças a ovs por 3 bytes e xnor por mais 3.

Lynn
fonte
Você poderá salvar bytes colocando um conjunto depois c+=, pois, por algum motivo, ele será convertido em uma lista para você.
xnor
(ah, sim, c+={i}-set(c[-n:])obras, para positiva nMas nimi apontou que. c[-n:]é errado n == 0, então eu não pode usar +=, e, portanto, esse truque -. muito ruim)
Lynn
11
@ Lynn Ah, entendo. reduceainda economiza bytes: lambda n,a:len(reduce(lambda c,i:[i][i in c[:n]:]+c,a,[])).
Xnor
7

R , 69 64 62 bytes

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

Experimente online!

Agradecemos a JayCe por sugerir algumas melhorias e a DigEmAll por mais um casal!

Giuseppe
fonte
Eu acho que o +na frente Fé para f(0,{})retornar 0?
21418 JayCe
@JayCe sim, um golfe clássico em conjunto com Fum valor de retorno pré-inicializado.
Giuseppe
11
uma pequena melhoria . Além disso, se a saída unária for aceita, você provavelmente poderá salvar alguns bytes.
Jayce
@JayCe encontrou mais alguns bytes!
Giuseppe
11
@JDL sim, uma pena a qidéia, mas ainda assim uma boa! Usar NAé menos bom do que usar, {}pois eu realmente me importo com o tamanho aqui (e na verdade não estou removendo elementos do cache).
Giuseppe
5

Haskell, 61 58 bytes

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

Experimente online!

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

Edit: -3 bytes graças a @Lynn.

nimi
fonte
5

05AB1E , 17 16 bytes

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

Experimente online!

Explicação

)                   # 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
Emigna
fonte
@nimi: Obrigado! Corrigido ao salvar um byte :)
Emigna 12/06
5

Kotlin , 82 69 bytes

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

Aceita a entrada como um IntArray, não o típico List<Int>(o que não deve ser um problema.) Isso usa a abordagem de "criar um histórico de cache e contar seu comprimento".

Experimente online!

Explicação

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

Criando uma lista vazia

O Kotlin não possui literais de coleção, mas possui algumas funções para criar novas coleções.

A maneira correta de criar um vazio List<Int>é simplesmente:

List<Int>()

mas é mais curto se abusarmos dos argumentos de tamanho e inicializador para fazer isso:

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

Como o gerador lambda retorna 0, o Kotlin deduz o tipo dessa lista como List<Int>, e o tamanho de 0 significa que esta lista está vazia.

Caracol_
fonte
4

Perl 6 , 48 bytes

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

Teste-o

{  # 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)
}
Brad Gilbert b2gills
fonte
4

Java 8, 96 bytes

Um lambda ao curry obtendo um tamanho de cache ( int) e lista de acesso (mutável java.util.List<Integer>) e retornando um 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;}

Experimente Online

Ungolfed

Isso usa os primeiros (até) sslots na lista de entrada para o cache.

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

Agradecimentos

  • bugfix graças a nimi
Jakob
fonte
4

Pitão ,  16 15 18 14  13 bytes

Guardado 1 byte graças a isaacg .

luaW-H>QGGHEY

Suíte de teste!

Esse desafio é muito adequado à uestrutura de Pyth .

Como funciona

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.
Mr. Xcoder
fonte
aW-H>QGGHbeats ?}H<GQG+HGpor 1
isaacg
@isaacg Thanks! Inicialmente +G*]H!}H>QG, mas quando jogava golfe eu realmente não pensava em W... Legal!
Xcoder
O que exatamente faz u?
dylnan
@dylnan ué um operador de redução com valor inicial. Assim como o de Jellyƒ
Mr. Xcoder
2

Japonês, 16 bytes

;£A¯V øX ªAiXÃAl

Tente


Explicação

                     :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
Shaggy
fonte
1

K4 , 42 40 bytes

Solução:

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

Exemplos:

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

Explicação:

Para a função interna, y é o cache, z é a solicitação e x é o tamanho do cache.

{*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

Notas:

Provavelmente existe uma maneira melhor de fazer tudo isso, mas essa é a primeira maneira que veio à mente.

A função pode ser executada assim por 36 bytes :

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

Alternativa - usando uma variável global para armazenar estado (não muito parecido com K), 42 bytes :

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

Flak cerebral , 172 bytes

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

Experimente online!

# 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)
<>({}[]<>)
Nitrodon
fonte
1

Gelatina , 18 bytes

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

Experimente online!

Leva a lista como o primeiro argumento e a capacidade de cache como segundo argumento.

Ṗɼṛ;ɼ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
dylnan
fonte
1

Ruby , 43 40 bytes

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

Experimente online!

Obrigado histocrat por raspar 3 bytes.

GB
fonte
11
Boa resposta! Você pode salvar um par de bytes por inicializar r como parte da lista de argumentos: ->s,a,*rque também fornece o recurso de bônus que o chamador pode preparar o cache passando argumentos extras :)
histocrat
Ah, e da mesma forma para converter xem uma matriz:.count{|*x|
histocrat 13/06
1

C (gcc) , 112 110 108 bytes

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

Experimente online!

Um pouco menos golfe

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;
}
teto
fonte
0

C (gcc) , 156 bytes

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

Experimente online!

Descrição:

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
LambdaBeta
fonte
Sugira em wmemset(c,-1,x)vez de n=m=0;for(i=0;i<x;++i)c[i]=-1, em n=m=i=s=0vez de i=s=0, em for(j=x;j--;)vez de for(j=0;j<x;++j)e em s||(c[n++]=_[i],m++,n%=x);vez deif(!s){c[n++]=_[i];m++;n%=x;}
roofcat 12/06
0

Geléia , 17 bytes

Ṗœ|Ṛḣ⁴$Ṛʋ\-;⁸e"ċ0

Experimente online!

Programa completo.

Argumento 1: pilha (Python 3 listde integers)
Argumento 2: n(Python 3 integer)

Erik, o Outgolfer
fonte
0

Ferrugem , 129 bytes

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

Experimente online!

Ungolfed

|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()
    }
}
Herman L
fonte