จำนวนแคช 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

9
รู้จักกันในชื่อBélády's anomalyและ FIFO เป็นตัวอย่างคลาสสิก ความผิดปกติคือมากมาย
virtualirfan

@dylnan ไม่ขอโทษ
orlp

คำตอบ:


11

JavaScript (ES6), 55 ไบต์

วิธีที่ # 1: แคชจะเขียนทับอินพุต

(cache_size)(list)จะเข้าในไวยากรณ์ currying

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

ลองออนไลน์!

อย่างไร?

เราเขียนทับป้อนข้อมูลอาร์เรย์a []กับแคชโดยใช้ตัวชี้แยกต่างหากkเริ่มต้นได้ที่0

เราใช้a.indexOf(x, k > n && k - n) < kเพื่อทดสอบว่าxอยู่ในแคชหรือไม่

แคชไม่สามารถเติบโตเร็วกว่าอาเรย์ดั้งเดิมได้ดังนั้นควรตรวจสอบแต่ละค่าว่าอยู่ภายในหรือเกินกว่าหน้าต่างแคช (เช่นindexOf()จะไม่ส่งคืน-1 )

ค่าอยู่ในแคชถ้ามันจะพบได้ที่ดัชนีระหว่างmax (0, k - n)และK - 1 (ทั้งขอบเขตรวม) ซึ่งในกรณีที่เราทำa [จริง] = x นี้มีผลเฉพาะคุณสมบัติของวัตถุต้นแบบที่อยู่เบื้องหลังa []แต่ไม่เปลี่ยนแปลงอาร์เรย์ a [] มิฉะนั้นเราจะทำa [k ++] = x

ตัวอย่าง

ด้านล่างนี้เป็นขั้นตอนที่แตกต่างกันสำหรับการป้อนข้อมูล[1, 1, 2, 3, 3, 2, 1, 4]ด้วยขนาดแคช2 :

  • เส้นขอบหนา: ตัวชี้แผนที่ ()
  • วงเล็บ: ตัวชี้แคชk
  • สีส้ม: หน้าต่างแคชปัจจุบัน
  • สีเหลือง: ค่าแคชหมดอายุ

วิธีที่ # 1


JavaScript (ES6), 57 ไบต์

วิธีที่ # 2: แคชถูกผนวกเข้าที่ส่วนท้ายของอินพุต

(cache_size)(list)จะเข้าในไวยากรณ์ currying

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

ลองออนไลน์!

อย่างไร?

เนื่องจากการป้อนข้อมูลอาร์เรย์a []รับประกันได้ว่าจะมีจำนวนเต็มไม่เป็นลบเราสามารถได้อย่างปลอดภัยผนวกแคชในตอนท้ายของa []โดยใช้หนึ่งเติมเต็ม~ xของแต่ละค่าx

เราใช้n * ~a.indexOf(~x, -n)เพื่อทดสอบว่า~ xถูกพบในค่าnสุดท้ายหรือไม่ เมื่อใดก็ตามที่การทดสอบนี้ล้มเหลวเราผนวก~ xเพื่อa []และเพิ่มจำนวนคิดถึงk

ตัวอย่าง

ด้านล่างนี้เป็นขั้นตอนต่าง ๆ สำหรับตัวอย่างเดียวกันกับข้างบนโดยใช้วิธีนี้ เนื่องจากค่าแคชถูกต่อท้ายส่วนท้ายของอาร์เรย์จึงไม่มีตัวชี้แคชที่ชัดเจน

วิธีที่ # 2


10

Haskell , 50 ไบต์

f n=length.foldl(\r x->[x|all(/=x)$take n r]++r)[]

ลองออนไลน์!

ขึ้นอยู่กับวิธีการของ Lynn ในการเก็บประวัติแคชทั้งหมดและใช้ความยาว เอาท์พุท unaryจะสั้นลงเล็กน้อย:

Haskell , 47 ไบต์

n?l=1<$foldl(\r x->[x|all(/=x)$take n r]++r)[]l

ลองออนไลน์!


9

Python 2 , 58 ไบต์

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

ลองออนไลน์!

ขอบคุณ ovs สำหรับ 3 ไบต์และ xnor อีก 3


คุณควรจะสามารถบันทึกไบต์ด้วยการตั้งค่าหลังจากc+=เนื่องจากด้วยเหตุผลบางอย่างมันจะแปลงเป็นรายการสำหรับคุณ
xnor

(อ่าใช่ใช้c+={i}-set(c[-n:])งานได้ผลในเชิงบวกnแต่ nimi ชี้ให้เห็นว่าc[-n:]มันเป็นสิ่งที่ผิดn == 0ดังนั้นฉันจึงใช้ไม่ได้+=และด้วยเหตุนี้เคล็ดลับ - เลวร้ายเกินไป)
ลินน์

1
@Lynn Ah ฉันเห็น ยังช่วยประหยัดไบต์:reduce lambda n,a:len(reduce(lambda c,i:[i][i in c[:n]:]+c,a,[]))
xnor

7

R , 69 64 62 ไบต์

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

ลองออนไลน์!

ขอบคุณ JayCe ที่แนะนำการปรับปรุงบางอย่างและ DigEmAll สำหรับคู่อื่น!


ฉันเดาว่า+ข้างหน้าFมีไว้f(0,{})เพื่อคืนค่า 0 หรือไม่
JayCe

@ JayCe yep กอล์ฟคลาสสิกควบคู่กับFเป็นค่าตอบแทนที่กำหนดไว้ล่วงหน้า
Giuseppe

1
improvemement ขนาดเล็ก นอกจากนี้ถ้ายอมรับเอาต์พุตแบบยูนารีคุณอาจบันทึกจำนวนไบต์ได้
JayCe

@JayCe พบบางไบต์เพิ่มเติม!
จูเซปเป้

1
@JDL ใช่เรื่องน่าอายเกี่ยวกับqแต่ก็ยังเป็นความคิดที่ดี การใช้งานNAนั้นดีกว่าการใช้งาน{}จริง ๆ เพราะฉันสนใจเรื่องความยาวของที่นี่ (และฉันก็ไม่ได้เป็นองค์ประกอบของแคช)
Giuseppe

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

05AB1E , 17 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

Kotlin , 82 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>()

แต่จะสั้นกว่านี้หากเราใช้ขนาดและ initializer ในทางที่ผิด

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

เนื่องจากแลมบ์ดาเครื่องกำเนิดคืน 0, Kotlin infers ประเภทของรายการนี้เป็น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 ไบต์

แลมบ์ดาแกงกะหรี่การขนาดแคช ( 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;}

ลองใช้ออนไลน์

Ungolfed

ใช้ช่องแรก (มากถึง) 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;
    }

กิตติกรรมประกาศ

  • แก้ไขข้อผิดพลาดขอบคุณnimi

4

Pyth ,  16 15 18 14  13 ไบต์

ที่บันทึกไว้ 1 ขอบคุณไบต์isaacg

luaW-H>QGGHEY

ชุดทดสอบ!

ความท้าทายนี้เหมาะกับuโครงสร้างของ Pyth มาก

มันทำงานอย่างไร

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... Nice!
นาย Xcoder

ไม่ว่าสิ่งที่uทำอย่างไร
dylnan

@dylnan uเป็นการลดค่าด้วยตัวดำเนินการค่าเริ่มต้น เช่นเดียวกับ Jelly'sƒ
Mr. Xcoder


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

K4 , 42 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

Ruby , 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|
ประวัติศาสตร์ 24

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

ลองออนไลน์!

ตีกอล์ฟน้อยลงเล็กน้อย

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]=-1, n=m=i=s=0แทนที่จะi=s=0, for(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




โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.