连续投票检测


51

Stack Exchange自动检测连续投票(当一个用户对另一位用户的许多帖子进行投票或否决时)并将其撤消。在这个挑战中,您将实现一个非常非常简单的“序列投票”检测器。

输入项

输入是代表投票列表的字符串。每个由两个字符组成的组代表一个投票-第一个是投票者,第二个是被投票的用户。例如,以下输入

ababbccd

可被分析为ab ab bc cd,代表a投票的b两次 b投票权的c一次,c投票权的d一次。

输入将仅包含小写字母,并且始终是大于0的偶数长度。您也无法对自己进行投票(因此,no aahh)。

输出量

出于此挑战的目的,串行投票被定义为任何给定用户对任何其他用户进行三次或更多次投票。

输出是多少票应为每个用户相反(即,许多票如何每个用户的互换,没有多少票,他们给了被逆转),格式[user][votes][user2][votes2]...。例如,输入ababababa上投票b四次)应输出 b4(四票已经从逆转ab)。

输出可以按照您想要的任何顺序进行,但是如上所述,输入和输出都必须是单个字符串。

测试用例

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

16
+1 nanananananananabatman测试用例。
9

Answers:


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字节

输出是按相反的字母顺序(za),但是根据您的允许的规则。

'“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “'”“'”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“ “'”“'”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“'“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” '“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“'”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”““”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“'”“'”“”“”“”“”“”“”“”“”“”“”“”“”“”“ “”“”“'”“”“”“”“”“”“”“”“”“”“”'“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” '“”“'”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“'”“”“”“”“”“”“”“”“”“”“”'“”“”“”“”“”“”“”“”'“”'“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “'”“'”“”“”“”“”“”“”“”“”“”“”“”“'”“”“”“”“”“”“”“”“ “”“”“'”“”“”“”“”“”“”“”“”“”“”'“”“”“”“”“”“”“”“” '“”“”“'”“”“”“”“”“”“”“”“”“”“”'“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”'“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”'“”“”“”“”“”“”“”“”“” “”“”“'”“”“”“”“”“”“”“”“”“”“”'“”“”“”“”“”“”“”“”'“”'“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “'”“'”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“ '“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“” “”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”'“”“'”“”“”“”“”“”“”“”“”“”“”“'”“”“”“”“”“”“”“”“”“”“”“” “'”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“'”“”“”“”“”“”“”“”“”“”“”“”“”“”“'”“”“”“”“”“”“”“”“”“”“”“”

说明

首先,给人一种难以理解的印象,这是它的基本操作:

  • 你有一个无限大小的任意大小的整数单元
  • 没有像Brainfuck中那样的内存指针。相反,您可以按单元在磁带上的位置取消引用单元。这意味着您可以“读取值#4”或“读取值#(读取值#4)”(双重引用)。
  • 您只能读写存储单元(不能像Brainfuck那样直接增加/减少)。
  • 您可以在表达式中增加/减少值。因此,要增加一个存储单元,您必须读取增加写入或以其他方式放置:write(x, inc(read(x)))
  • 有while循环和三元条件只能检查零与非零。

该程序如下使用磁带。变量名称将在下面的伪代码中使用。此外,本文档还记录了第一个版本(1830字节)。请参阅底部的修改,以了解自那时以来所做的更改。

  • 储存格0:可变q
  • 细胞1:变量apch
  • 单元格2:变量hashv
  • 细胞3:变量br
  • 单元格4:变量aal
  • 单元格5:保留为0,以标记十进制数字字符串的“结尾”
  • 单元格6–95:向后存储十进制数字的字符串
  • 单元格96–121:存储要从用户a(96)减至z(121)的票数(字母的ASCII码减一)。
  • 单元格4657–7380:记住已遇到多少个投票者/投票者组合。这些单元格只有4个可能的值:0=尚未见过,-1=见过一次,-2=见过两次,-3=见过任何次数大于2的次数。

该算法基本上如下进行:

  • 继续阅读成对的字符ab。计算哈希值(a-2)*(a-1)+b-1,它对于字母a–z的每个组合都是唯一的。
  • 检查该哈希值(*hash)处的存储单元。如果是-3,则该用户已经有资格进行投票删除,因此请递增*(b-1)。否则,递减*hash。如果是现在 -3,用户刚刚成为资格投票取出后三种表现,因此增加*(b-1)3
  • 之后,以相反的顺序浏览字符(za),然后输出需要扣除票数的字符。这需要手动将整数除以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循环的返回值。

编辑 2,1796 →1791:如果我不使用6–95单元格,而是将十进制数字存储在负数单元格中(从1开始),则表明程序稍小。作为一项额外的奖励,该计划不再仅限于10票!

编辑3,1791→1771:不是指定的结果*(ch = l + 95)v,我现在把它分配给q,然后分配移动v = q到while条件,采取代码1777个字节。然后交换qv在磁带上的位置,因为q现在比常见1 v

编辑4,1771→1762: Du。初始化hash为1而不是0的时间要短9个字节。哈希码现在增加了1,这无关紧要。

编辑5,1762→1745:如果我初始化q并设置r为1而不是0,我必须-1在适当的位置撒一些s来使它正确,而且似乎都被抵消了-除了while v { --v; [...] }循环现在需要执行更少的迭代之外,我可以这样说while --v { [...] },即短了26个字符。

编辑6,1745→1736:相反{ r = 1; ++q },我们可以编写q = *((r = 1)+1)+1。这取决于q位于可变插槽2中的事实。如果它在#1插槽中,它甚至会更短,但是整个程序的整体长度会更长。

编辑7,1745→1727:恢复编辑6,而是通过将最里面的while循环内联到计算数字ASCII码的表达式中来实现保存,该表达式也以1​​736字节结尾...但是随后保存了一个减量指令(9字节) )更改((++r) - 11) ? r :(r - 10) ? ++r :

编辑8,1727→1626:重做哈希计算。现在,它减少了一个while循环。单元格位置现在是其实际的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,1606→1577:我观察到aa2均递减到0在while循环,因此,如果我能配对p与任一那些,但ch,我不会需要初始化p0(花费29个字节)。原来我可以通过交换p和来做到这一点r。现在,最新的变量分配(及其在代码中的出现频率)为:

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 2015年

1
@ETHproductions:不过,在打高尔夫球时,我碰巧修正了这个限制:)
Timwi 2015年

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.

另一个版本通过反转对开始,这在其他位置节省了两个字节:a)仅选择每个字符串中的第一个字符,:c而不是Wf=选择第二个字符。b)我们不需要在第二个RLE之前再次排序,因为这些对已经主要按照剩余字符进行了排序。


FWIW Q第二个答案应该是q出于非测试包装的目的。
彼得·泰勒

@PeterTaylor我一直都这样做-.-
Martin Ender

我知道这是次要的细节,但是将转换3为列表进行比较是一个不错的技巧。我只是出于自己的娱乐目的解决了它,并因为使用了而在那儿丢失了一个字节0=2>。否则,除了最后一步使用::\ 代替之外,我最终得到的结果几乎与您的第一个解决方案相同Wf%
Reto Koradi

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,DigitalTrauma保存9 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的第二个字符(又称为“投票对象”)将该键添加到哈希表中。(我们不必将所有内容都初始化为零;我们可以这样做awk。)

    • END{...}:这只是意味着“在处理完整个文件之后,这是下一步。”

    • for(x in c)printf x c[x]:相当不言自明。打印每个键及其对应的值。


&等于\0in sed
User112638726 2015年

@ User112638726不知道,谢谢
Doorknob

减少了一点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,例如。
门把手

哦,是的,我不好!
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]');

测试用例:

在较高的级别上,此代码使用键-值对填充对象,该对值将投票接收者映射到投票数量,例如{ b:7, a:3 },然后将它们连接成一个for循环的字符串。该代码位于eval表达式中,以允许for在arrow函数中使用而不需要在{ }和上花费字节;return r

(为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 2015年

1
一方面,您可以删除var。谁在乎污染代码高尔夫的全球范围?;)
门把手

另外,/(\w{2})/g也可以/../g-我们已经知道输入只是字母,重复一个(或两个)字符比短{2}。如果您有兴趣,可以看看我的JavaScript答案(并对此问题发表评论)。欢迎来到PGCC!
apsillers

4

数学,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保存1个字节$g{$'}。不幸的是,$$'这行不通。

3

纯粹打击(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="")
  }
}

这里有很大的改进空间。

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.