删除字符串


39

许多语言都有内置的方法来消除重复项,或者“去重复”或“唯一化”列表或字符串。不太常见的任务是“删除”字符串。也就是说,对于每个出现的字符,都会保留前两次出现。

这是一个示例,其中应删除的字符用标记^

aaabcbccdbabdcd
  ^    ^ ^^^ ^^
aabcbcdd

您的任务是完全实现此操作。

规则

输入是单个(可能为空)字符串。您可以假定它仅包含ASCII范围内的小写字母。

输出应为一个字符串,其中已删除的所有字符至少已在字符串中出现两次(因此,保留了最左边的两个匹配项)。

您可以使用字符列表(或单例字符串)来代替字符串,但是输入和输出之间的格式必须一致。

您可以编写程序或函数,并使用我们的任何标准方法来接收输入和提供输出。

您可以使用任何编程语言,但是请注意,默认情况下,这些漏洞是禁止的。

这是,因此以字节为单位的最短有效答案为准。

测试用例

每对线都是一个测试用例,输入然后是输出。



xxxxx
xx
abcabc
abcabc
abcdabcaba
abcdabc
abacbadcba
abacbdc
aaabcbccdbabdcd
aabcbcdd

排行榜

这篇文章底部的Stack Snippet会根据答案a)生成排行榜,a)是每种语言的最短解决方案列表,b)则是整体排行榜。

为确保您的答案显示出来,请使用以下Markdown模板以标题开头。

## Language Name, N bytes

N您提交的文件大小在哪里。如果您提高了分数,则可以将旧分数保留在标题中,方法是将它们打掉。例如:

## Ruby, <s>104</s> <s>101</s> 96 bytes

如果要在标头中包含多个数字(例如,因为您的分数是两个文件的总和,或者您想单独列出解释器标志罚分),请确保实际分数是标头中的最后一个数字:

## Perl, 43 + 3 (-p flag) = 45 bytes

您还可以将语言名称设置为链接,然后该链接将显示在代码段中:

## [><>](http://esolangs.org/wiki/Fish), 121 bytes


5
单例字符串...字符串?
dkudriavtsev

Answers:



15

JavaScript(ES6),42 48

编辑一个巨大的6个字节保存@@ Neil

s=>s.replace(k=/./g,c=>(k[c]+=c)[11]?'':c)

说明:我使用对象的属性'a'...'z' k存储每个字符的信息(在这种情况下,对象k是一个正则表达式,只是为了保存字节)。这些属性最初是undefined。在javascript中,将数字添加为undefined给出NaN(非常明智),但是添加字符串'X'给出"undefinedX"-长度为10的字符串(傻)。添加更多字符,您将获得更长的字符串。如果为给定字符获得的字符串长于11,则不会将该字符复制到输出。

测试

F=
s=>s.replace(k=/./g,c=>(k[c]+=c)[11]?'':c)

test=`

xxxxx
xx
abcabc
abcabc
abcdabcaba
abcdabc
abacbadcba
abacbdc
aaabcbccdbabdcd
aabcbcdd`.split`\n`
for(i=0;i<test.length;)
  a=test[i++],b=test[i++],r=F(a),
  console.log(r==b?'OK':'KO',a,'->',r,b)


严格来说,空行是测试用例之一。
尼尔

@Neil ok添加了空字符串测试
edc65 '16

如果切换到数组输入和输出,则可以使用.filter保存另外12个字符。 v=>v.filter(x=>!(v[x]+=x)[11])。在“未定义” hack上的荣誉。
Grax32

@Grax thanx但太不一样了。应该自己发布
edc65 '31

14

Python 2,48个字节

lambda s:reduce(lambda r,c:r+c*(r.count(c)<2),s)

c[r.count(c)/2:]是的同长替代c*(r.count(c)<2)


49个字节:

r=''
for c in input():r+=c*(r.count(c)<2)
print r

12

视网膜,17字节

(.)(?<=\1.*\1.+)

在线尝试!

简单的正则表达式替换-如果一个字符已经出现两次,则将其匹配,然后将其删除。


我还尝试了一个循环和一个重复的组{2},两个都有18个字节。
科比

1
我有14个使用了最近添加的功能。;)
Martin Ender 2016年

我知道有事 我看着极限,也许不是那个极限。我再检查一次。
科比

3
嗯,我想我找到了马丁的答案。我以前尝试时遇到了一些麻烦,我想是因为我没有考虑过重复数据删除在多行输入中的工作方式。扰流板(添加5个字节以启用每行模式):retina.tryitonline.net/…–
FryAmTheEggman

@FryAmTheEggman-很好,我没有找到这个。随意添加答案-我认为这与我的答案太不一样了,我用它编辑它感到不自在:P。谢谢!
科比

6

Brachylog,25个字节

.v|s.g:.z:1a
:2fl<3
he~t?

在线尝试!验证所有测试用例

说明

这样做是因为s - Subset将与大亚第一统一,从而例如对于"aaa"它会尝试"aa"之前"a"

  • 主要谓词:

      .v         input = Output = ""
    |          Or
      s.         Output is an ordered subset of the input
      g:.z       Zip each character of the output with the output itself
      :1a        Apply predicate 1 on each element of the zip
    
  • 谓词1:检查所有字符最多只出现两次。输入=[String:Char]

    :2f        Find all valid outputs of predicate 2 (i.e. one output per occurence
                   of the char)
    l<3        There are less than 3 occurences
    
  • 谓词2:获取一个字符的出现。输入=[String:Char]

    he         Take a character of the string in the input
      ~t?      That character is the char of the input
    

6

> <>,22字节

i:0(?;::9g:}2(?o{1+$9p

在线尝试!使用代码箱跟踪到目前为止的计数。

i                       Read a char c of input
 :0(?;                  Halt if EOF
      :                 Make a copy - stack has [c c] at the top
       :9g              Get count stored at (c, 9)
          :}            Copy the count and move to bottom of stack
            2(?o        If the count is less than 2, output c
                {1+     Move the count back to the top of the stack and increment
                   $9p  Update cell at (c, 9)
                        [Instruction pointer moves to start as ><> is toroidal]

6

J,20 15字节

#~(3>[+/@:={:)\

这定义了一个接受并返回字符串的单子函数。在这里尝试。用法:

   f =: #~(3>[+/@:={:)\
   f 'abaacbb'
abacb

说明

我切换到了其他一些解决方案使用的相同算法,因为事实证明它更短...

#~(3>[+/@:={:)\  Input is y.
  (          )\  For each prefix of y:
          =        compute the equality vector
     [     {:      of the prefix and its last element, and
      +/@:         take its sum. Now we have a vector r such that y[i] has its
                   r[i]'th occurrence at position i.
   3>              Mark those coordinates where r[i] < 3.
#~               Remove the non-marked characters from y.

6

Haskell,40 39字节

foldl(\s c->s++[c|filter(==c)s<=[c]])""

用法示例:foldl(\s c->s++[c|filter(==c)s<=[c]])"" "aaabcbccdbabdcd"-> "aabcbcdd"

c如果c到目前为止所有s 的字符串在字典上小于或等于单例字符串,则保留下一个char [c]

编辑:@xnor通过将列表理解切换为来保存一个字节filter。谢谢!


您的替代方法可以filter(==c)s<=[c]节省一个字节。
xnor

5

Perl,22个字节

21字节代码+ 1 for -p

s/./$&x(2>${$&}++)/ge

用法

perl -pe 's/./$&x(2>${$&}++)/ge' <<< 'aaabcbccdbabdcd'
aabcbcdd

5

C,57字节

f()用字符串调用以删除重复项。该函数修改其参数。由于for-loop声明,因此需要C99 。

f(char*p){for(char*s=p,m[256]={0};*s=*p;s+=++m[*p++]<3);}

您不能将的声明s放入的第一条语句中for吗?
Martin Ender

在C99中可以。我只是没有,因为我喜欢保持高尔夫C89兼容。
owacoder '16

5

JavaScript(ES6),35个字节

s=>s.filter(c=>(s[c]=(s[c]|0)+1)<3)

将字符数组作为输入并返回经过删除的数组。


真好 您可以c=>(s[c]=-~s[c])<3节省一些字节。
ETHproductions

我想念您可以使用数组作为输入,并使用编写了一个函数map。打高尔夫球,看起来基本上像你的。主要的区别是分配,如果您将其切换,将节省一些字节。尝试s.filter(c=>(s[c]=s[c]+1|0)<3)33个字节。编辑:糟糕,错过了我上方的评论,这甚至更好:)
1

4

PowerShell v2 +,31个字节

$args-replace'(.)(?<=\1.*\1.+)'

使用与Kobi的Retina答案相同的正则表达式,仅封装在PowerShell -replace运算符中。之所以可行,是因为两者都在后台使用了.NET风格的正则表达式。

或者,不使用正则表达式,则为56个字节

$b=,0*200;-join([char[]]$args[0]|%{"$_"*($b[$_]++-lt2)})

创建一个$b预填充了0s 的辅助数组。将输入字符串强制转换$args[0]char-array,将其通过loop传递|%{...}。每次迭代都将当前字符输出$_为一个字符串,再"$_"乘以一个布尔值,然后乘以一个布尔值(仅在辅助数组中的适当点小于此值时$TRUE(隐式转换为1此处))2(即,我们尚未两次看到此char)。字符串的结果集合封装在paren中,并-join一起编辑以形成单个输出字符串。这留在管道上,输出是隐式的。


正则表达式是无与伦比的。:)我认为哈希表比没有regex:的变量数组好$b=@{};-join($args|% t*y|?{++$b.$_-lt3})
mazzy

1
@mazzy对于不带正则表达式和您的代码的变体,它必须是比PowerShell 2更高的版本。因此,我想我会保持不变。不过,您可以将代码发布为单独的答案!
AdmBorkBork

哈希表是否出现在3.0版中?好。谢谢。
mazzy

4

Mathematica,39个字节

Fold[If[Count@##<2,Append@##,#]&,{},#]&

匿名函数。以字符列表作为输入,并返回已删除的列表作为输出。使用折叠列表并拒绝一式三份元素的方法,这不太复杂。


4

05AB1E,12个字节

vyˆ¯y¢O3‹iy?

说明

v            # for each char in input
 yˆ          # push to global array
   ¯y¢O3‹i   # if nr of occurrences are less than 3
          y? # print it

在线尝试


4

MATL,8字节

t&=Rs3<)

在线尝试!

说明

t      % Input string implicitly. Push another copy
&=     % Matrix of all pairwise equality comparisons of string elements
R      % Keep only upper triangular part, making the rest of the entries zero
s      % Sum of each column. This gives a vector with number of occurrences
       % of the current character up to the current position
3<     % True for entries that are less than 3
)      % Use as logical index into initial copy of the input. Display implicitly

假设输入'aaababbc',堆栈在指示的语句之后包含以下内容:

  • t

    'aaababbc'
    'aaababbc'
    
  • t&=

    'aaababbc'
    [ 1 1 1 0 1 0 0 0;
      1 1 1 0 1 0 0 0;
      1 1 1 0 1 0 0 0;
      0 0 0 1 0 1 1 0;
      1 1 1 0 1 0 0 0;
      0 0 0 1 0 1 1 0;
      0 0 0 1 0 1 1 0;
      0 0 0 0 0 0 0 1 ]
    
  • t&=R

    'aaababbc'
    [ 1 1 1 0 1 0 0 0;
      0 1 1 0 1 0 0 0;
      0 0 1 0 1 0 0 0;
      0 0 0 1 0 1 1 0;
      0 0 0 0 1 0 0 0;
      0 0 0 0 0 1 1 0;
      0 0 0 0 0 0 1 0;
      0 0 0 0 0 0 0 1 ]
    
  • t&=Rs

    'aaababbc'
    [ 1 2 3 1 4 2 3 1 ]
    
  • t&=Rs3<

    'aaababbc'
    [ true true false true false true false true ]
    
  • t&=Rs3<)

    'aabbc'
    

4

视网膜,14字节

D`(.)(?<=\1.*)

验证所有测试用例。%启用每行模式)

使用新的“重复数据删除”阶段,可以比Kobi的方法节省几个字节。Deduplicate会收集与正则表达式的所有匹配项的列表,并将除第一个之外的所有内容替换为空字符串。正则表达式匹配在字符串中已经出现过的字符,这意味着将保留前两个字符。



3

K,18字节

  g:{x{?x@<x}@,/2#'=x}
  g "abc"
"abc"
  g "aaabcbccdbabdcd"
"aabcbcdd"

  /k4 request test vectors from internet
  R:"GET /raw/ftHe0bpE HTTP/1.0\r\nHost: pastebin.com\r\n\r\n"
  t:+0N 2#t@1_&|\(0=#:)'t:1_"\r\n"\:`:http://pastebin.com:80 R 

  /k4 no internet? use a file called "t.txt" in current directory
  t:+0N 2#0:`:t.txt

  /k6?
  t:+0N 2#0:"t.txt"

  /visually inspect test cases
  g't[0]
(();"xx";"abcabc";"abcdabc";"abacbdc";"aabcbcdd")

  /do all tests pass?
  |/ t[1] {$[0=#x;0=#y;x~y]}' g't[0]
1b

K4可以免费下载;K6正在开发中。如果您已经下载KDB,你可以进入K的反斜杠

可能会很容易看出这一点,但首先要注意一些语法:g:x设置gx{x+1}是带有参数x的函数。在K中,函数的第一个参数是x(第二个是y,第三个是z。不需要第四个)。

现在:

x:"aaabcbccdbabdcd"

=x表示组x,它产生:

"abcd"!(0 1 2 10;3 5 9 11;4 6 7 13;8 12 14)

2#'手段2取(从),每个产生

"abcd"!(0 1;3 5;4 6;8 12)

如您所见,这些是每个字符的前两个匹配项的偏移量。该2可以推广。

,/意味着加入每个人,通常被称为raze。这将使我们获得字典的值。因此,,/"abcd"!(0 1;3 5;4 6;8 12)产生:

0 1 3 5 4 6 8 12

我们需要排序。{x@<x}@是K程序员经常看到的一个习惯用法(Q称为asc),表示x是x的等级。分解:

  <0 1 3 5 4 6 8 12
0 1 2 4 3 5 6 7

返回排序数组的索引,我们要从原始数组中获取索引。x@y表示x在y处,因此这将使用排序的索引对数组进行索引(如果有任何意义)。

  {x@<x}@0 1 3 5 4 6 8 12
0 1 3 4 5 6 8 12

现在我们只是将其索引到原始数组中。我们可以x@在这里说,但是K支持一个非常强大的概念,在这里我们可以利用它:函数应用程序正在建立索引。这意味着a[0]可能正在查找的第零个槽,a或者正在将应用于0调用的函数a。我们需要的原因@以前{x@<x}是因为x<y手段XS低于YS:以K运营商有一个二元形式(两个参数)和一元的形式(单参数)是来自APL。Q没有这种“矛盾性”。


欢迎来到PPCG!很棒的第一答案。:)
Martin Ender

我有一些问题。1. K4与您链接的语言(Q / kdb +)是否相同?2.您能否显示如何在输入上调用函数或如何格式化testVectors.txt中的项目?
丹尼斯,

@丹尼斯1.是的。按反斜杠从Q到g"aaabcbccdbabdcd"
K。2

好,谢谢。无法使文件部分正常工作,但是g"..."可以解决问题。不幸的是,您的代码返回aabbcc了input abc
丹尼斯

@Dennis您可能做错了:{x{?x@<x}@,/2#'=x}"abc"肯定会返回"abc""aabbcc"如果您错过了?独特性,它将返回。
地质车


2

Java 8 lambda,90个字符

i->{int[]o=new int[128];String r="";for(char c:i.toCharArray())if(++o[c]<3)r+=c;return r;}

非高尔夫版本:

public class Q86503 {

    static String detriplicate(String input) {
        int[] occurences = new int[128];
        String result = "";
        for (char c : input.toCharArray()) {
            if (++occurences[c] < 3) {
                result += c;
            }
        }
        return result;
    }
}

为所有ascii字符创建一个数组。如果出现一个字符,则相应的计数器将增加。如果大于2,则字符不会附加到结果字符串中。很容易,很短;)


2

Perl 6,27字节

{.comb.grep({++%.{$_} <3})}

说明:

{.comb.grep({++%.{$_} <3})}
{                         } # a function
 .comb                      # get all the characters in the argument
      .grep({           })  # filter
               %.           # an anonymous hash (shared between calls to grep)
             ++  {$_}       # increment the value at the current key (current letter).
                            # if the key doesn't exist, it defaults to 0 (then gets incremented)
                      <3    # return True if it wasn't seen 3 times

(注意:Perl 6不像其姐姐Perl 5那样“面向高尔夫”。所以,是的,在之前的空格<是必需的。The %.{}是匿名哈希)。



2

SmileBASIC,77 72 69 68字节

DIM R[#Y]READ S$WHILE""<S$Q=ASC(S$)INC R[Q]?SHIFT(S$)*(R[Q]<3);
WEND

解释:

DIM R[128] 'array to store letter frequencies
READ S$ 'get input string
WHILE""<S$ 'much shorter than LEN(S$)
 Q=ASC(S$) 'get ascii value of first character in S$
 INC R[Q]
 ?SHIFT(S$)*(R[Q]<3); 'remove the first character of S$, and print it if there are less than 3 occurrences.
WEND

欢迎来到ppcg!不错的第一篇文章!
Rɪᴋᴇʀ

1

普通Lisp 127

(lambda(s)(map()(lambda(x)(flet((p(b)(1+(position x s :start b))))(setf s(remove x s :start(p(p 0))))))(remove-duplicates s))s)

精美印刷

(lambda (s)
  (map nil
       (lambda (x)
         (flet ((p (b)
                  (1+ (position x s :start b))))
           (setf s (remove x s :start (p (p 0))))))
       (remove-duplicates s))
  s)

1

Q,52字节

q)f2:{x asc raze{distinct 2#where x}each x~'/:distinct x}
q)f2 each testList
"xx"
"abcabc"
"abcdabc"
"abacbdc"
"aabcbcdd"
q)

1

K,27字节

    f:{x{x@<x}@,/{?2#&x}'x~'/:?x}
    testList:("xxxxx";"abcabc";"abcdabcaba";"abacbadcba";"aaabcbccdbabdcd")
    f'testList
("xx";"abcabc";"abcdabc";"abacbdc";"aabcbcdd")

1

红宝石79 62 57字节

这非常笨拙,但是我不确定目前是否能打得更好。欢迎任何打高尔夫球的建议。在线尝试!

编辑: -17字节感谢Value Ink通过建议采用高尔夫球手的方式来删除一式三份字符。-5个字节,删除.uniq方法。

->s{s.chars.map{|a|s[s.rindex a]=""while s.count(a)>2};s}

取消高尔夫:

def g(s)
 s.chars.each do |a|
  while s.count(a) > 2
   i = s.rindex(a)
   s[i] = ""
  end
 end
 return s
end

62位元组:->s{s.chars.uniq.map{|a|s[s.rindex a]=""while s.count(a)>2};s}
Value Ink

1

JavaScript,30个字节

v=>v.filter(x=>!(v[x]+=x)[11])

使用@ edc65提出的方法进行计数,但要使用数组过滤器。第一次出现字符时,对象值将获得“未定义”加字符(即“ undefinedx”)。下一次对象值变为“ undefinedxx”。

此后,v [x] [11]返回true,当与not运算符组合使用false时,意味着已经出现两次的字符将被过滤。


0

Javascript(使用外部库)(80字节)

这是一个好人!没有赢,但是很有趣

n=>{a={};return _.From(n).Where(x=>{b=a[x]?a[x]++:a[x]=1;return b<2}).Write("")}

链接到lib:https : //github.com/mvegh1/Enumerable/

代码说明:Method接受字符串,库将其解析为char数组,Where子句是一个复杂的过滤谓词,用于检查'a'哈希映射是否存在当前char。如果存在,则增加计数器,否则设置为1。如果<2,则谓词(和当前字符)通过,否则失败

在此处输入图片说明


您可以避免使用,return但是将函数设为括号中的表达式的逗号分隔列表n=>(a={},_From(n)....)。最后一个表达式是返回值。在您的Where函数中,您可以b通过与赋值或增量的结果进行比较来完全消除中间物x=>(a[x]?a[x]++:a[x]=1)<2
apsillers

最后,你能避免使用字符串分割省略号,并使用在所有(和保存字节)的外部库filterjoin[...n].filter(...).join("")。当改变翻转真/假逻辑Wherefilter
apsillers

啊,好观察!稍后我会仔细看看您的建议
applejacks01 '16

0

Clojure,72个字节

#(apply str(reduce(fn[r c](if(<(count(filter #{c}r))2)(conj r c)r))[]%))

这么多字节...


0

帕斯卡(FPC),103字节

var a:array['a'..'z']of word;c:char;begin repeat read(c);inc(a[c]);if a[c]<3then write(c)until eof end.

在线尝试!

说明:

var a:array['a'..'z']of word; //used for counting occurences of characters in the input
                              //array indices are accessed by chars
    c:char;
begin
  repeat
    read(c);                  //read a character from input
    inc(a[c]);                //increment the count of that character (its number in array)
    if a[c]<3 then write(c)   //if this is character's 1st or 2nd occurence, output it
  until eof                   //go back to reading if input is not read completely
end.
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.