連続投票の検出


51

Stack Exchange は、シリアル投票(1人のユーザーが他のユーザーの投稿の多くをアップ投票またはダウン投票する場合)を自動的に検出し、それを取り消します。この課題では、非常に単純な「連続投票」検出器を実装します。

入力

入力は、投票のリストを表す文字列です。2文字のグループはすべて投票を表します。最初のグループは投票者で、2番目のグループは投票対象のユーザーです。たとえば、次の入力

ababbccd

解析することができab ab bc cd、かつ表しa上の投票b二回、 b上の投票c一度、とcに投票をd一度。

入力は小文字のみで構成され、常に0を超える偶数長になります。また、自分自身に投票することもできません(そのため、いいえaaまたはhh)。

出力

このチャレンジのために、連続投票は、特定のユーザーが他のユーザーに3回以上投票することとして定義されます。

出力は、ユーザごとに逆転されなければならない(つまり、多くの票どのようにどのように多くの票である形式で、各ユーザーが逆転して、彼らは与えられていることではないどのように多くの票逆転しました)[user][votes][user2][votes2]...。たとえば、abababab(4回a投票する)の入力はb出力する必要があります b4(4票がからに逆転しaましたb)。

出力は任意の順序にすることができますが、入力と出力の両方が上記のように単一の文字列でなければなりません。

テストケース

In                            Out
---------------------------------------------------------------------------
abababcbcbcbcbbababa          b7a3
edfdgdhdfgfgfgih              g3
jkkjjkkjjkkjljljljmlmlnmnmnm  j6k3m3
opqrstuv                      <none>
vwvwwvwv                      <none>
xyxyxyxyxyxyxyzyzyzyxzxzxz    y10z3
nanananananananabatman        a8
banana                        <none>

16
nanananananananabatmanテストケースの場合は+1 。
9

回答:


6

Pyth、22バイト

pM_srSsfttTtMM.gkcz2 8

オンラインで試す:デモンストレーションまたはテストスイート

説明:

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

例:

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

34

読み取り不可1830 1796 1791 1771 1762 1745 1736 1727 1626 1606 1577バイト

出力はアルファベットの逆順(zto a)ですが、許容されると思われる規則に従っています。

'"" "" "" "" "" "" "" "" "" "" "" "" "'" "" "" "" "" "" "" "" "" "" "" " "'" "'" "" "" "" "" "'" ""' "" "" "" "" "" "" "" "" "" "" '"" "" ""' " "'" "'" "" "" "'" "" "" "'" "" "" '"" "'" "" "" "" "" "" "" "" '""'""' "" "'" "" "" "" "" "" "" ""' "" '""' "" "'" "" "" "" "'" "" "" "" " '""' "" '""' "" "'" "" "" "" "" "'" "'" "" "" "" "" "" "" "" "" "" "' "" '""' "" '"" "" "" "'" "" "" "" '"" "'" "" "" "" "" "" '""' "" '"" "" "" "" "" "" "" '"" "'" "" "" "" "'" "" "" "'" "" "" "" '"" "'" " "" "" "" "" "" "" '""' "" "'" "'" "'" "'" "" "" "" "" "" "" "" "" '" "" "" "" "" "" "" '"" "" "" "'" "'" ""' "" "" "" "" "'" "'" "'" ""'" "'" "" "" '""' "" '""' "" '""' "" '""' "" "" "'" "'" "'" "" ""' "" '""' "" "" "'" "'" "'" "" ""' "" '""' "" "'" "" ""' "" "" "'" "' ' "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'" "" "" "" "'"" "" "" "" "" "" "" "" "" "" "" "" '"" "" "" "" "" "" "" "" "" "" "" " '"" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "' "" '""' "" "" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'""' "" "" "'" "" ""' "" '""' "" '""' "" '""' "" '"" "" "'" "'" "'" "'" "'" "" "" '""' "" '""' "" '""' "" '""' "" "" "'" "'" "'" "" ""' "" '""' "" "" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" " '"" '""' "" '""' "" '""' "" "" "'" "'" "'" "'" "'" "'" "'" "" "" ""' "" "" "" "" "" "'"' "" "" "" "'" ""' "" "" "" "" '"" "" "" "" "" "" " "" '"" "" "" ""' "" "'" "" "" ""' "" '"" "" "" "'" "" "" "'" ""' """" "" '"" "" ""' "" "'" "" "" "'" "" "" "'" "'" "'" ""' "" "" "" "''" "" "" "" "" "" "" '"" "" "" "" "" "'" "'" "" "" "" "" "'" "'" "'" "' "" '""' "" "" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'""' "" '""' "" "" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "'" "' "'" "'" "" "" "" "'" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '"" "" "" ""' "" "'" "" "" "" ""' "" "" "" "" "" "" "" "" "" "" "" """" "" "" "" "" '"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "'" "'" "" "" "" ' "" "'" "" "" "" "" ""' "" '"" "" ""' "" "" "" "'" "'" "" '"" "" ""'"" "'" "" '"" "" "'" "" "" "" '""' "" '"" "'" '"" "" "" "'" "" "" "" " "'" "" "" "" ""' "" '"" "'" "'" "" "" ""' "" '""' "" """ '""' "" "'" "'" "" "" "" '""' "" '"" """ '""' "" "'" "'" "" "" "" '""' "" '"" "

説明

まず、Unreadableでできることの印象を得るために、基本的な操作を次に示します。

  • 任意のサイズの整数セルの無限のテープがあります
  • Brainfuckのようなメモリポインタはありませ。代わりに、テープ上の位置によってセルを間接参照します。これは、「値#4を読み取る」または「値#(値4を読み取る)」を読み取ることができることを意味します(二重参照)。
  • メモリセルの読み取りまたは書き込みのみが可能です(Brainfuckのように直接インクリメント/デクリメントすることはできません)。
  • 式内で値をインクリメント/デクリメントできます。したがって、メモリセルをインクリメントするには、readincrementwrite、または別にputする必要がありますwrite(x, inc(read(x)))
  • whileループとゼロ以外のチェックのみをチェックできる3項条件があります。

このプログラムは次のようにテープを使用します。変数名は、以下の擬似コードで使用されます。また、これは最初のバージョン(1830バイト)を文書化します。それ以降の変更点については、下部の編集をご覧ください。

  • セル0:変数q
  • セル1:変数apch
  • セル2:変数hashv
  • セル3:変数br
  • セル4:変数aal
  • セル5:10進数の文字列の「終了」を示すために0のまま
  • セル6〜95: 10進数の文字列を逆方向に格納します
  • セル96〜121:ユーザーから差し引く投票数a(96)からz(121)(文字のASCIIコード-1)を保存します。
  • セル4657〜7380:どの投票者/投票者の組み合わせに何回遭遇したかを覚えておいてください。これらの細胞は、唯一の4つの可能な値があります。0まだ見ていない=、-1一度見=、-2二度見する=、-3= 2倍以上の任意の数より多く見。

アルゴリズムは基本的に次のように進みます。

  • 文字aとのペアを読み続けbます。ハッシュ値を計算します(a-2)*(a-1)+b-1。これは、文字a〜zのすべての組み合わせに対して一意です。
  • そのハッシュ値(*hash)のメモリセルを確認します。の場合-3、ユーザーは投票の削除の対象になっているため、をインクリメントします*(b-1)。それ以外の場合は、デクリメントします*hash。それはだ場合は、今 -3、ユーザーはただいるなる 3つの出現後に投票除去の対象なので、増分*(b-1)によって3
  • この後、文字を逆順(zto a)で処理し、投票を差し引く必要がある文字を出力します。これには、数値を10進数に変換するために10で整数を手動で除算する必要があります。

すべてが明確になったので、これはプログラムが擬似コードのように見えるものです。

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

編集 1、1830 →1796: whileループの戻り値を1箇所で再利用できることを認識しました。

編集 2、1796 →1791:セル6〜95を使用する代わりに、負の数のセルに小数桁を格納すると(–1以降)、プログラムはわずかに小さくなります。追加ボーナスとして、プログラムは10票に制限されなくなりました!

編集3、1791→1771:*(ch = l + 95) to の結果を割り当てる代わりにv、今度はそれを割り当ててから、while条件にq割り当てv = qを移動し、コードを1777バイトにします。その後の位置を交換qし、vので、テープにq今よりも1より一般的ですv

編集 4、1771 →1762:ダウ。hash0ではなく1に初期化すると、9バイト短くなります。ハッシュコードはもう1つになりましたが、問題ではありません。

編集5、1762→1745:私は初期化した場合qr1ではなく0に、私はいくつかの振りかけるしなければならない-1場所でのが右のそれを作るために、そしてすべて相殺するようだ-ことを除いてwhile v { --v; [...] }、ループが今1回の少ない反復を実行する必要があります、これwhile --v { [...] }は26文字短いということでできます。

編集6、1745→1736:の代わりに{ r = 1; ++q }、と書くことができますq = *((r = 1)+1)+1。これqは、可変スロット#2 にあるという事実に依存しています。スロット#1にある場合、これはさらに短くなりますが、プログラム全体は全体的に長くなります。

編集 7、1745 →1727:編集6を元に戻し、代わりに数字のASCIIコードを計算する式に最も内側のwhileループをインライン化することで保存を達成しました。 )に変更((++r) - 11) ? r :(r - 10) ? ++r :ます。

編集 8、1727 →1626:ハッシュ計算を修正しました。現在は、whileループが1つ少なくなっています。セルの位置は、実際のASCIIコードになっています(1ずつずれていません)。変数が異なる頻度で発生するようになったため、変数をテープ上の異なる場所にシャッフルしました。

編集9、1626→1606:よりクレイジーなインライン化。最初のwhileループの本体は、次のようになります。

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

変数の割り当てはほぼ完全に変更されました。

編集10、→1577 1606:私はそれを観察aし、a2両方のループが、私はペアリングができればしばらく0までデクリメントされpますが、それらのいずれかではないch、私は初期化する必要はありませんp0(29のバイトがかかります)。スワップpr。最新の変数割り当て(およびコード内での発生頻度)は次のとおりです。

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)

1
どのよう見novemvigintillionの投票は2 * 10 ^ 90バイトの文字列を必要とする、と10 ^ 24バイトの現在可能な最小のボリュームはギザの大ピラミッドの約1/3のサイズである、私はあなたが持っているとは思いません心配することは何でも。;)
ETHproductions

1
@ETHproductions:それにもかかわらず、プログラムのゴルフ中にたまたまその制限を修正しました:)
ティムウィ

22

CJam、23バイト

ランレングスパーティー!

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

または

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

すべてのテストケースを実行する

説明

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.

他の場所に2つのバイトを節約対、反転させることにより他のバージョンの開始:各文字列の最初の文字を選択するa)が唯一である:c代わりに、Wf=第二を選択します。b)2番目のRLEの前に再度並べ替える必要はありません。これは、ペアがすでに残りの文字で既に並べ替えられているためです。


Q2番目の回答のFWIWは、qテストラッパー以外の目的である必要があります。
ピーターテイラー

@PeterTaylor私がやることすべての時間-.-
マーティン・エンダー

私はそれが小さな詳細であることを知って3いますが、比較のためにリストに変換することは素晴らしいトリックです。私は自分の娯楽のためにそれを解決し、を使用し0=2>たのでそこにバイトを失いました。それ以外の場合は、最後のステップでは::\ なく使用することを除いて、最初のソリューションとほぼ同じになりWf%ました。
レトコラディ

10

Bash、95 94 85 81バイト

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

エレガントでありながら長い最初のソリューション...

おかげUser112638726でバイトを保存するためsedに9を保存するため、DigitalTraumaをfold、そしてライナーP.とより4を保存するためawksubstr

それがどのように機能するかを見るために、入力を見てみましょうabababcbcbcbcbbababa

  • 後にfold -2(2の幅に行を折り返す)、我々は持っています

    ab
    ab
    cb
    cb
    cb
    cb
    ba
    ba
    ba
    
  • sort | uniq -c-cに非常に気の利いたフラグされuniq、我々が得るものは何回入力内の各ラインが表示されますの数を出力します)

          3 ab
          3 ba
          4 cb
    
  • 最後のawkコマンドを見てみましょう。

    • $1>2:レコード1(同じ票の数)が2(つまり3以上)より大きい場合のみ出力します。つまり、2以下の数字で始まる行は無視します。

    • {c[substr($2,2)]+=$1}:数値が2より大きい場合、cレコード2の2番目の文字(別名、投票者)をキーとして使用して、ハッシュテーブルにその数値を追加します。(すべてをゼロに初期化する必要はありませんawk。それを行います。)

    • END{...}:これは単に「ファイル全体を処理した後、次に何をすべきか」を意味します。

    • for(x in c)printf x c[x]:かなり自明です。すべてのキーとそれに対応する値を印刷します。


&equivelantある\0sedの中で
User112638726

@ User112638726知らなかった、ありがとう
ドアノブ

それを少し減少sed -r 's/.(.)/\1\n/g'|awk '{a[$1]++}END{for(i in a)printf (a[i]>2)?i a[i]:y}
User112638726

@ User112638726 bacadaたとえば、input では失敗します。
ドアノブ

ああ、そうだね!
ユーザー112638726

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]');

テストケース:

高いレベルで、このコードは、投票受信者を投票数にマッピングするキーと値のペアをオブジェクトに追加し、{ b:7, a:3 }それらをforループ内の文字列に結合します。コードはeval式に含まforれて{ }おり、にバイトを費やす必要なく矢印関数内で使用できます;return r

(3バイトを節約するためのuser81655の小道具!)

evalコードの説明:

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

6

Haskell、103バイト

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)

使用例:f "jkkjjkkjjkkjljljljmlmlnmnmnm"->"k3j6m3"

使い方:

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 

6

JavaScript(ES6)、195 174 169 167 158バイト

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")

テスト


1
PPCGへようこそ:) JS でのゴルフのコツはこちらこちらです。私はJSのことを本当によく知っているわけではありませんが、幸せなゴルフ:)
FryAmTheEggman

1
一つには、vars を削除できます。コードゴルフのグローバルスコープの汚染を気にする人はいますか?;)
ドアノブ

また、/(\w{2})/g単に/../g入力することができます-入力は文字のみであり、1つ(または2つ)の文字を繰り返すことはより短いことをすでに知っています{2}。興味のある方は、このチャレンジに対する私のJavaScriptの回答をご覧ください(そして質問にコメントしてください)。PGCCへようこそ!
apsillers

4

Mathematicaの、110の 100 99バイト

g=Cases[Tr@#,#2,All]&;""<>g[g[BlockMap[$,Characters@#,2],i_*_/;i>2]/.$->Last,i_*x_:>x<>ToString@i]&

3

Perl、86 84 83バイト

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

これは、82バイトと-pコマンドライン引数の1です。

$ echo xyxyxyxyxyxyxyxyzyzyzyxzxzxz | perl -p 86.pl
y11z3


やや自由:

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
  • 更新84 grepをインライン化して2バイトを節約
  • 更新83の${$'}代わりにグローバル一時変数を使用して1バイトを保存します$g{$'}。残念ながら、$$'機能しません。

3

Pure Bash、151

思っていたよりも長いが、ここにある。

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

連想配列のインデックスを使用して、必要なカウントを実行します。bashバージョン4.0以降が必要です。


1

PHP 247文字

(痛い)

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

説明した

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

他の答えを覗かずにこれをやった。これは私がこれまで取り組んだ中で最も難しいコードゴルフです。すべての最適化を歓迎します。


0

R、221バイト

コード

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="")}

食べない

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="")
  }
}

ここには改善の余地がたくさんあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.