Szeregowe wykrywanie głosowania

51

Stack Exchange automatycznie wykrywa głosowanie seryjne (gdy jeden użytkownik głosuje lub głosuje wiele postów innego użytkownika) i odwraca go. W tym wyzwaniu zaimplementujesz bardzo prosty detektor „głosowania seryjnego”.

Wejście

Dane wejściowe to ciąg znaków reprezentujący listę głosów. Każda grupa dwóch znaków reprezentuje głos - pierwsza to głosujący, a druga głosujący użytkownik. Na przykład następujące dane wejściowe

ababbccd

może być parsowany jako ab ab bc cdi reprezentuje agłosowanie bdwa razy, bgłosowanie craz i cgłosowanie draz.

Dane wejściowe będą się składać tylko z małych liter i zawsze będą miały równą długość> 0. Nie możesz także głosować na siebie (więc nie aalub hh).

Wynik

Na potrzeby tego wyzwania głosowanie seryjne definiuje się jako głosowanie danego użytkownika na dowolnym innym użytkowniku trzy lub więcej razy.

Dane wyjściowe określają, ile głosów należy cofnąć dla każdego użytkownika (to znaczy, ile głosów na każdego użytkownika zostało cofniętych, a nie ile głosów oddanych zostało odwróconych), w formacie [user][votes][user2][votes2].... Na przykład wkład abababab( agłosowanie bczterokrotnie) powinien dać wynik b4(cztery głosy zostały odwrócone z ana b).

Dane wyjściowe mogą być w dowolnej kolejności, ale dane wejściowe i wyjściowe muszą być pojedynczymi ciągami, jak opisano powyżej.

Przypadki testowe

In                            Out
---------------------------------------------------------------------------
abababcbcbcbcbbababa          b7a3
edfdgdhdfgfgfgih              g3
jkkjjkkjjkkjljljljmlmlnmnmnm  j6k3m3
opqrstuv                      <none>
vwvwwvwv                      <none>
xyxyxyxyxyxyxyzyzyzyxzxzxz    y10z3
nanananananananabatman        a8
banana                        <none>
Klamka
źródło
16
+1 dla nanananananananabatmanprzypadku testowego.
9

Odpowiedzi:

6

Pyth, 22 bajty

pM_srSsfttTtMM.gkcz2 8

Wypróbuj online: pakiet demonstracyjny lub testowy

Wyjaśnienie:

pM_srSsfttTtMM.gkcz2 8
                 cz2     chop the input into pairs
              .gk        group these pairs by their value
           tMM           discard the first char in each pair in each group
       fttT              discard all groups, that contain less than three pairs
      s                  concatenate all groups to get a list of chars
     S                   sort all chars
    r                8   run-length-encoding
   s                     concatenate all (count,char) pairs 
  _                      reverse the order
pM                       print each element without separator

Przykład:

input:   ededgdhdfgfgfgihed
chop:    ['ed', 'ed', 'gd', 'hd', 'fg', 'fg', 'fg', 'ih', 'ed']
group:   [['ed', 'ed', 'ed'], ['fg', 'fg', 'fg'], ['gd'], ['hd'], ['ih']]
discard: [['d', 'd', 'd'], ['g', 'g', 'g'], ['d'], ['d'], ['h']]
discard: [['d', 'd', 'd'], ['g', 'g', 'g']]
concat.: ['d', 'd', 'd', 'g', 'g', 'g']
sort:    ['d', 'd', 'd', 'g', 'g', 'g']
rle:     [[3, 'd'], [3, 'g']]
concat.: [3, 'd', 3, 'g']
reverse: ['g', 3, 'd', 3]
print:   g3d3
Jakube
źródło
34

Nieczytelny , 1830 1796 1791 1771 1762 1745 1736 1727 1626 1606 1577 bajtów

Dane wyjściowe są w odwrotnej kolejności alfabetycznej ( zdo a), ale zgodnie z regułami, które wydają się dozwolone.

„” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ „” „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „„ ”„ ”„ ”„ ” „” „” „” „” „„ ”„ ”„ „” „” „” „” „„ ”„ „” „” „” „” „” „” „”„” „” „” „” „„ ”„ ”„ ”„ „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ „” „„ ”„ „” „„ ”„ ”„ ”„ ” „” „” „” „” „„ ”„ „” „„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „” „” „”„” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „” „” „„ ”„ „” „” „” „„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„” „„ ”„ ”„ „” „” „„ ”„ „” „” „” „” „„ ”„ „” „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ „” „” „” „„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „„ ”„ ”„ „” „„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „” „” „”„” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „„ ”„ ”„ ” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „„ ”„ ”„ „” „„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „” „” „” „„” „” „” „” „” „” „” „„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ ”„ „” „” „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „„ ”„ ”„ „” „„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „” „” „”„” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ „” „” „” „„ ”„ ”„ ” „” „” „” „” „„ ”„ ”„ ”„ „” „” „” „„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ”„” „” „” „” „„ ”„ ”„ ”„ „” „” „” „„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „” „„ ”„ „” „” „” „” „” „” „” „„ ”„ „” „” „” „” „” „” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ „” „„ ”„ ”„ ”„ ”„ ”„ ”„” „” „” „” „„ ”„ „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„ ” „” „” „” „„ ”„ ”„ ”„ ”„ „” „” „” „„ ”„ „” „” „”„” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”„” „” „” „” „” „” „” „„ ”„ ”„ ”„ ”„ ”„ ”

Wyjaśnienie

Po pierwsze, aby zorientować się, co może zrobić Nieczytelny, oto jego podstawowe działanie:

  • Masz nieskończoną taśmę komórek liczb całkowitych o dowolnym rozmiarze
  • Zdajesz nie posiada wskaźnik pamięć jak w brainfuck; zamiast tego wyrejestrowujesz komórki według ich położenia na taśmie. Oznacza to, że możesz „odczytać wartość # 4” lub „odczytać wartość # (odczytać wartość 4)” (podwójne dereferencje).
  • Możesz tylko czytać lub zapisywać komórki pamięci (nie bezpośrednio zwiększać / zmniejszać, jak w Brainfuck).
  • Możesz zwiększać / zmniejszać wartości w wyrażeniu. Dlatego, aby zwiększyć komórkę pamięci trzeba czytać , przyrost , pisać , lub inaczej umieścić: write(x, inc(read(x))).
  • Istnieją pętle while i trójskładnikowe warunki, które mogą sprawdzać tylko zero lub zero.

Ten program używa taśmy w następujący sposób. Nazwy zmiennych zostaną użyte w pseudokodzie później poniżej. Dokumentuje także pierwszą wersję (1830 bajtów); zobacz zmiany u dołu, które zmieniły się od tego czasu.

  • Komórka 0: zmiennaq
  • Komórka 1: zmienne a, p,ch
  • Komórka 2: zmienne hash,v
  • Komórka 3: zmienne b,r
  • Komórka 4: zmienne aa,l
  • Komórka 5: pozostaje 0, aby zaznaczyć „koniec” ciągu cyfr dziesiętnych
  • Komórki 6–95: przechowuje ciąg cyfr dziesiętnych do tyłu
  • Komórki 96–121: przechowują liczbę głosów, które należy odjąć od użytkowników a(96) do z(121) (kod ASCII litery minus jeden).
  • Komórki 4657–7380: pamiętaj, które kombinacje wyborców / wyborców napotkano ile razy. Komórki te mają tylko 4 możliwe wartości: 0= jeszcze nie widział, -1= widział raz, -2= widział dwa razy, -3= widział dowolną liczbę razy więcej niż 2.

Algorytm zasadniczo działa w następujący sposób:

  • Czytaj dalej pary znaków ai b. Oblicz wartość skrótu (a-2)*(a-1)+b-1, która jest unikalna dla każdej kombinacji liter a – z.
  • Sprawdź komórkę pamięci przy tej wartości skrótu ( *hash). Jeśli tak -3, użytkownik jest już uprawniony do usunięcia głosu, więc zwiększaj *(b-1). W przeciwnym razie spadek *hash. Jeśli jest to teraz -3 , użytkownik po prostu stać się kwalifikują się do usunięcia głosowanie po trzech zdarzeń, więc zwiększyć *(b-1)przez 3.
  • Następnie przejrzyj postacie w odwrotnej kolejności ( zdo a) i wypisz te, które wymagają odliczenia głosów. Wymaga to ręcznego dzielenia liczb całkowitych przez 10, aby przełożyć liczbę na cyfry dziesiętne.

Po tym wszystkim wyjaśniono, że tak wygląda program jako pseudokod:

// Read pairs of characters
while (a = read) + 1 {
    b = read

    // Calculate hash = (a-1)*(a-2)/2 + b-1
    // This also sets a = b-1
    hash = 0
    while --a {
        aa = a
        while --aa {
            ++hash
        }
    }
    while --b {
        ++a
        ++hash
    }

    // If this combination has just been seen for the third time,
    // increment *a by 3; if more than third time, increment *a by 1
    *a = (*hash + 3) ? ((--*hash) + 3 ? *a : (*a+3)) : (*a+1)
}

// Loop through the characters z to a
l = 27
while --l {                     // l loops from 26 to 1 (not 0)
    (v = *(ch = l + 95)) ? {    // 'a' is ASCII 97, but cell 96
        print (ch+1)            // print the votee

        // Now we need to turn the number v into decimal.
        // p points to where we are storing decimal digits.
        p = 5

        while v {
            // Integer division by 10 (q=quotient, r=remainder)
            r = (q = 0)
            while v {
                --v
                (++r - 10) ? 1 : {
                    r = 0
                    ++q
                }
            }
            // Store digit ASCII character
            *(++p) = r + 48     // 48 = '0'
            v = q
        }

        // Now output all the digit ASCII characters in reverse order
        while *p {
            print *(--p + 1)
        }

    } : 1
}

Edycja 1, 1830 → 1796: Uświadomiłem sobie, że mogę ponownie użyć wartości zwracanej pętli while w jednym miejscu.

Edycja 2, 1796 → 1791: Okazuje się, że program jest nieco mniejszy, jeśli zamiast komórek 6–95 przechowuję cyfry dziesiętne w komórkach o numerach ujemnych (–1 wzwyż). Jako dodatkowy bonus program nie jest już ograniczony do 10⁹⁰ głosów!

Edycja 3, 1791 → 1771: Zamiast przypisywać wynik *(ch = l + 95)do v, teraz przypisuję go do, qa następnie przenoszę przypisanie v = qdo warunku while, przenosząc kod do 1777 bajtów. Następnie zamień lokalizację qi vna taśmie, ponieważ qjest teraz o 1 bardziej powszechna niż v.

Edytuj 4, 1771 → 1762: Duh. Inicjalizacja hashna 1 zamiast 0 jest krótsza o 9 bajtów. Kod skrótu jest teraz o 1 więcej, co nie ma znaczenia.

Edycja 5, 1762 → 1745: Jeśli zainicjuję qi rdo 1 zamiast 0, muszę posypać kilka -1s miejscami, aby wszystko było w porządku, i wydaje się, że wszystko się anuluje - poza tym, że while v { --v; [...] }pętla musi teraz wykonać jedną mniejszą iterację, co mogę zrobić, mówiąc o while --v { [...] }26 znaków krótszych.

Edycja 6, 1745 → 1736: Zamiast tego { r = 1; ++q }możemy pisać q = *((r = 1)+1)+1. Zależy to od faktu, że qznajduje się w zmiennej szczelinie nr 2. Gdyby znajdował się w gnieździe nr 1, byłby jeszcze krótszy, ale cały program byłby ogólnie dłuższy.

Edycja 7, 1745 → 1727: Cofnięto Edycja 6 i zamiast tego osiągnięto oszczędność poprzez wstawienie najbardziej wewnętrznej podczas pętli do wyrażenia obliczającego cyfrowy kod ASCII, który również kończy się na 1736 bajtach ... ale następnie zapisał instrukcję dekrementacji (9 bajtów ), zmieniając ((++r) - 11) ? r :na (r - 10) ? ++r :.

Edytuj 8, 1727 → 1626: Przerobiono obliczanie wartości skrótu. Teraz używa o jedną mniej pętli while. Lokalizacje komórek mają teraz swoje rzeczywiste kody ASCII (już nie wyłączone o 1). Przetasowane zmienne w różnych miejscach na taśmie, ponieważ występują one teraz z inną częstotliwością.

Edytuj 9, 1626 → 1606: Bardziej szalone wstawianie. Ciało pierwszej pętli while wygląda teraz mniej więcej tak:

// b = next char
*(b = (hash = read)) = {

    // hash = b + (a-1)*(a-2)/2
    while (a2 = --a) {
        while --a2 {
            ++hash
        }
    }

    // If this combination has just been seen for the third time,
    // increment *b by 3; if more than third time, increment *b by 1
    (*hash + 3) ? ((--*hash) + 3 ? *b : (*b+3)) : (*b+1)
}

a przypisanie zmiennych zmieniło się prawie całkowicie.

Edycja 10, 1606 → 1577: Zauważyłem, że ai a2są zarówno zmniejszany do 0 w podczas pętli, więc jeśli mogę powiązać pz żadnym z nich, ale nie z ch, nie trzeba zainicjować pdo 0(która kosztuje 29 bajtów). Okazuje się, że mogę to zrobić, zamieniając pi r. Najnowsze przypisania zmiennych (i ich częstotliwość występowania w kodzie) to teraz:

0 = v (3)                    (total  3)
1 = hash (6), r (5), ch (2)  (total 13)
2 = b (4), q (5)             (total  9)
3 = a (3), p (5)             (total  8)
4 = a2 (3), l (4)            (total  7)
Timwi
źródło
1
Biorąc pod uwagę, że głosowanie novemvigintillion wymagałoby ciągu 2 * 10 ^ 90 bajtów, a obecna najmniejsza możliwa objętość 10 ^ 24 bajtów jest w przybliżeniu 1/3 wielkości Wielkiej Piramidy w Gizie , nie sądzę, że masz cokolwiek się martwić. ;)
ETHproductions
1
@ETHproductions: Mimo to podczas gry w golfa udało mi się naprawić to ograniczenie :)
Timwi
22

CJam, 23 bajty

Długa impreza!

q2/$e`{3a>},e~Wf=$e`Wf%

lub

qW%2/$e`{3a>},e~:ce`Wf%

Uruchom wszystkie przypadki testowe

Wyjaśnienie

q2/   e# Read input and split into pairs.
$e`   e# Sort and run-length encode - this tallies the pairs.
{     e# Filter the tallies...
  3a> e#   Keep only those which start with a 3 or greater.
},    e# Now we need to group the remaining pairs.
e~    e# Run-length decode the remaining pairs.
Wf=   e# Select the second character from each pair (the one being voted on).
$e`   e# Tally the characters by sorting and RLE'ing again.
Wf%   e# Reverse each pair, because CJam's RLE has the number first and the character last.

Druga wersja zaczyna się od odwrócenia par, co pozwala zaoszczędzić dwa bajty w innym miejscu: a) wybranie pierwszego znaku w każdym ciągu jest tylko :czamiast Wf=wyboru drugiego. b) Nie musimy sortować ponownie przed drugim RLE, ponieważ pary zostały już posortowane głównie według pozostałej postaci.

Martin Ender
źródło
FWIW Qdruga odpowiedź powinna być qdla celów bez opakowania testowego.
Peter Taylor,
@PeterTaylor Robię to cały czas -.-
Martin Ender
Wiem, że to drobny szczegół, ale przekonwertowanie 3listy na listę do porównania jest fajną sztuczką. Rozwiązałem to tylko dla własnej rozrywki i straciłem bajt, ponieważ użyłem 0=2>. W przeciwnym razie skończyłem z prawie tym samym, co twoje pierwsze rozwiązanie, z wyjątkiem użycia ::\ zamiast Wf%do ostatniego kroku.
Reto Koradi,
10

Bash, 95 94 85 81 bajtów

fold -2|sort|uniq -c|awk '$1>2{c[substr($2,2)]+=$1}END{for(x in c)printf x c[x]}'

Eleganckie, ale długie pierwsze rozwiązanie na początek ...

Dzięki User112638726 do zapisywania bajt z sed, DigitalTrauma do zapisywania 9 W fold, a Rainer P. za uratowanie 4 więcej z awk„s substr!

Aby zobaczyć, jak to działa, weźmy wkład abababcbcbcbcbbababa.

  • Po fold -2(zawiń linię do szerokości 2) mamy

    ab
    ab
    cb
    cb
    cb
    cb
    ba
    ba
    ba
    
  • Po sort | uniq -c( -cjest bardzo fajną flagą, uniqktóra wyświetla liczbę, ile razy każda linia pojawia się na wejściu), otrzymujemy

          3 ab
          3 ba
          4 cb
    
  • Teraz sprawdźmy ostatnie awkpolecenie:

    • $1>2: Przesyłaj rzeczy tylko wtedy, gdy rekord 1 (czyli liczba identycznych głosów) jest większy niż 2 (to znaczy ≥ 3). Innymi słowy, zignoruj ​​dowolny wiersz zaczynający się od liczby ≤ 2.

    • {c[substr($2,2)]+=$1}: Jeśli liczba jest większa niż 2, dodaj tę liczbę do ctabeli mieszającej, używając drugiego znaku rekordu 2 (aka głosowanie-ee) jako klucza. (Nie musimy inicjować wszystkiego do zera; awkrobi to za nas).

    • END{...}: Oznacza to po prostu „po przetworzeniu całego pliku, oto co dalej.”

    • for(x in c)printf x c[x]: Dość oczywiste. Wydrukuj każdy klucz i odpowiadającą mu wartość.

Klamka
źródło
&jest równoważne z \0in sed
User112638726
@ User112638726 Nie wiedziałem o tym, dzięki
Klamka
Trochę go zmniejszyłemsed -r 's/.(.)/\1\n/g'|awk '{a[$1]++}END{for(i in a)printf (a[i]>2)?i a[i]:y}
User112638726,
@ Użytkownik112638726 To się nie powiedzie bacadana przykład dla danych wejściowych .
Klamka
O tak, mój zły!
User112638726,
8

JavaScript, 114 113 110

f=s=>eval('o={},s.replace(/../g,m=>s.search(`^((..)*${m}){3}`)?0:o[c=m[1]]=~~o[c]+1);r="";for(v in o)r+=v+o[v]');

Przypadki testowe:

Na wysokim poziomie ten kod zapełnia obiekt parami klucz-wartość, które mapują odbiorców głosów na liczbę głosów, na przykład, { b:7, a:3 }a następnie łączą je w ciąg w forpętli. Kod jest evalwyrażeniem umożliwiającym użycie forfunkcji strzałki bez konieczności wydawania bajtów na { }i ;return r.

( Proponuje użytkownikowi 81655 zapisanie trzech bajtów!)

Objaśnienie evalkodu:

o={},                             // object to hold name/vote mapping
s.replace(/../g,                  // for each pair of chars in input
  m=>s.search(`^((..)*${m}){3}`)  // see if pair appears 3 times
                                  //   (0 if true, -1 if not)
     ?0                           // if not, do nothing
     :o[c=m[1]]=~~o[c]+1          // if yes, increment the property named after
                                  //   the second character in the pair
);
r="";                       // return string
for(v in o)r+=v+o[v]        // populate string with characters and vote totals
apsillery
źródło
6

Haskell, 103 bajty

import Data.Lists
f s|c<-chunksOf 2 s,b<-[e!!1|e<-c,countElem e c>2]=nub b>>= \q->q:show(countElem q b)

Przykład użycia: f "jkkjjkkjjkkjljljljmlmlnmnmnm"->"k3j6m3"

Jak to działa:

c<-chunksOf 2 s                      -- split the input into lists of 2 elements
b<-[e!!1|e<-c,countElem e c>2]       -- for every element e of that list take the 2nd
                                     -- char if there are more than 2 copies of e
nub b>>= \q->q:show(countElem q b)   -- take every uniq element thereof and append
                                     -- the number how often it appears 
nimi
źródło
6

JavaScript (ES6), 195 174 169 167 158 bajtów

s=v=>eval("a={},b={},e='';(v.match(/../g)).forEach(c=>{a[c]=(a[c]||0)+1});for(var k in a){d=k[1];a[k]>2&&(b[d]=(b[d]||0)+a[k])};for(var k in b){e+=k+b[k]};e")

Test

Gavin.Paolucci.Kleinow
źródło
1
Zapraszamy do PPCG :) Mamy kilka wskazówek dla golfa w JS tutaj i tutaj . Sam nie znam JS wystarczająco dobrze, aby naprawdę pomóc, ale chętnie
gram w
1
Po pierwsze możesz usunąć vars. Kogo obchodzi zanieczyszczenie globalnego zasięgu w golfie kodowym? ;)
Klamka
Ponadto, /(\w{2})/gmożna po prostu być /../g- już wiemy, wejście jest tylko litery i powtarzając jeden (lub dwa) znaków jest krótszy niż {2}. Jeśli jesteś zainteresowany, możesz przejrzeć (i skomentować pytania) moją odpowiedź JavaScript na to wyzwanie. Witamy w PGCC!
apsillers,
4

Mathematica, 110 100 99 bajtów

g=Cases[Tr@#,#2,All]&;""<>g[g[BlockMap[$,Characters@#,2],i_*_/;i>2]/.$->Last,i_*x_:>x<>ToString@i]&
alephalpha
źródło
3

Perl, 86 84 83 bajtów

s/../$h{$&}++/eg;@l=%l=map{/./;$h{$_}>2?($',${$'}+=$h{$_}):()}keys%h;$"="";$_="@l"

To 82 bajty plus 1 dla -pargumentu wiersza poleceń:

$ echo xyxyxyxyxyxyxyxyzyzyzyxzxzxz | perl -p 86.pl
y11z3


Nieco golfisty:

s/../$h{$&}++/eg;     # construct hash %h with pair counts

@l = %l = map         # assign to array via hash to filter dupes
{                     
  /./;                # match the first character

  $h{$_}>2?           # filter on 3 or more identical votes
  (                   # return a 2 element list (k/v pair for %l):
    $',               # $POSTMATCH: the 2nd character (votee)
    ${$'} += $h{$_}   # increment votee total votes, value is new total
  )
  :()
}
keys %h;              # iterate the unique pairs

$" = "";              # set $LIST_SEPARATOR to empty string
$_ = "@l"             # implicit join using $";  $_ gets printed with -p
  • aktualizacja 84 Zapisz 2 bajty, wstawiając grep
  • aktualizacja 83 Zapisz 1 bajt, używając globalnych zmiennych tymczasowych ${$'}zamiast $g{$'}. Niestety $$'nie działa
Kenney
źródło
3

Pure Bash, 151

Dłużej niż się spodziewałem, ale oto jest.

declare -A a n
for((;v<${#1};v+=2));{((a[${1:v:2}]++));}
for u in ${!a[@]};{((a[$u]>2))&&((n[${u:1}]+=a[$u]));}
for u in ${!n[@]};{ printf $u${n[$u]};}

Używa asocjacyjnego indeksowania tablic, aby wykonać niezbędne zliczanie. Wymaga wersji bash 4.0 lub nowszej.

Cyfrowa trauma
źródło
1

PHP 247 znaków

(ouch)

$f='';for($i=0;$i<strlen($s);$i=$i+2){$a[]=$s[$i].$s[$i+1];}$r=[];for($i=0;$i<count($a);$i++){$t=array_count_values($a);$c=$t[$a[$i]];if($c>=3){$r[$a[$i][1]][$a[$i][0]]=$c;}}for($i=0;$i<count($r);$i++){$f.=key($r).array_sum(current($r));next($r);}

Wyjaśniono

// Test Case
$s = 'nanananananananabatman';

// Final result here
$f = '';

// Seperate strings into array in 2 character chunks
for ($i = 0; $i < strlen($s); $i = $i + 2)
{
    $a[] = $s[$i] . $s[$i + 1];
}

// Make an array of data
// The first level of array has voted on user as key
// Inside of that array is a dictionary with the voter user as the key, and the number of votes as the value
$r = [];
for ($i = 0; $i < count($a); $i++)
{
    $t = array_count_values($a);
    $c = $t[$a[$i]];
    if ($c >= 3)
    {
        $r[$a[$i][1]][$a[$i][0]] = $c;
    }
}

// Combine votes from different users to the same user into the final result string
for ($i = 0; $i < count($r); $i++)
{
    $f .= key($r) . array_sum(current($r));
    next($r);
}

echo $f;

Zrobił to bez zerkania na inne odpowiedzi. To najtrudniejszy golf golfowy, z jakim się zmierzyłem. Z zadowoleniem przyjmuję wszystkie optymalizacje.

Gęś
źródło
0

R, 221 bajtów

kod

f=function(s){t=strsplit(gsub("(.{2})","\\1 ", s)," ")[[1]];z=table(t)[table(t)>2];n=substr(names(z),2,2);x=data.frame(y=z,t=n);a=aggregate(x$y,by=list(x$t),sum);for(i in nrow(a):1)cat(as.character(a[i,1]),a[i,2],sep="")}

bez golfa

f <- function(s){
  l <- gsub("(.{2})", "\\1 ", s)
  t <- strsplit(l," ")[[1]]
  z <- table(t)[table(t)>2]
  n <- substr(names(z),2,2)
  x <- data.frame(y=z,t=n)
  a <- aggregate(x$y, by=list(x$t),sum)
  for(i in nrow(a):1){
    cat(as.character(a[i,1]),a[i,2],sep="")
  }
}

Jest tu dużo miejsca na ulepszenia.

Mutador
źródło