Детализировать строку

39

Во многих языках есть встроенные способы избавления от дубликатов, «дедупликации» или «унификации» списка или строки. Менее распространенная задача - «удалить дубликаты» строки. То есть для каждого появившегося символа сохраняются первые два вхождения.

Вот пример, где символы, которые должны быть удалены, помечены ^:

aaabcbccdbabdcd
  ^    ^ ^^^ ^^
aabcbcdd

Ваша задача - реализовать именно эту операцию.

правила

Ввод - единственная, возможно, пустая строка. Вы можете предположить, что он содержит только строчные буквы в диапазоне ASCII.

Выходные данные должны быть единственной строкой со всеми удаленными символами, которые уже встречались в строке, по крайней мере, дважды (таким образом, самые левые два вхождения сохраняются).

Вместо строк вы можете работать со списками символов (или одиночными строками), но формат должен быть согласованным между вводом и выводом.

Вы можете написать программу или функцию и использовать любой из наших стандартных методов получения ввода и предоставления вывода.

Вы можете использовать любой язык программирования , но учтите, что эти лазейки по умолчанию запрещены.

Это , поэтому самый короткий действительный ответ - измеренный в байтах - выигрывает.

Тестовые случаи

Каждая пара строк представляет собой один контрольный пример, за которым следует ввод, а затем вывод.



xxxxx
xx
abcabc
abcabc
abcdabcaba
abcdabc
abacbadcba
abacbdc
aaabcbccdbabdcd
aabcbcdd

Leaderboard

Фрагмент стека в нижней части этого поста создает таблицу лидеров из ответов а) в виде списка кратчайшего решения для каждого языка и б) в качестве общей таблицы лидеров.

Чтобы убедиться, что ваш ответ обнаружен, начните его с заголовка, используя следующий шаблон уценки:

## 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
Одиночные струны ... струнные
дкудрявцев

Ответы:

15

JavaScript (ES6), 42 48

Редактировать Колоссальные 6 байтов сохранены thx @Neil

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

Объяснение: Я использую свойства 'a' ... 'z' объекта kдля хранения информации для каждого символа (в данном случае объект k является регулярным выражением просто для сохранения байтов). Эти свойства изначально undefined. В javascript добавление числа к undefinedдает NaN(вполне разумно), но добавление строки «Х» дает "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)

edc65
источник
Строго говоря, пустая строка - это один из тестов.
Нил
@Neil хорошо добавил тест пустой строки
edc65
Если вы переключитесь на массив ввода и вывода, вы можете использовать .filter, чтобы сохранить еще 12 символов. v=>v.filter(x=>!(v[x]+=x)[11]), Слава о "неопределенном" взломать.
Grax32
@Grax спасибо, но слишком разные. Должен опубликовать это сам
edc65
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
XNOR
источник
12

Сетчатка , 17 байт

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

Попробуйте онлайн!

Простое регулярное выражение замены - сопоставьте символ, если он уже появился дважды, и удалите его.

Коби
источник
Я также попробовал цикл и повторную группу с{2} обоими по 18 байтов.
Коби
1
У меня есть 14, используя недавно добавленную функцию. ;)
Мартин Эндер
Я знал, что что-то было. Я посмотрел на пределы, вероятно, не тот. Я проверю снова.
Коби
3
Ах, я думаю, что нашел ответ Мартина. У меня были некоторые проблемы, когда я пытался раньше, я думаю, потому что я не думал, как дедупликация будет работать на многострочном вводе. Спойлер (с 5 байтами, добавленными для включения режима для каждой строки): retina.tryitonline.net/…
FryAmTheEggman
@FryAmTheEggman - Хорошо, я не нашел этого. Не стесняйтесь добавлять ответ - я думаю, что он слишком отличается от моего ответа, и мне было неудобно редактировать его :P. Благодарность!
Коби
6

Брахилог , 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
    
Fatalize
источник
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]
Sp3000
источник
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.
Zgarb
источник
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если строка всех cs до сих пор лексикографически меньше или равна единственной строке [c].

Редактировать: @xnor сохранил байт, перейдя от понимания списка к filter. Благодарность!

Ними
источник
Ваш вариант может сделать, filter(==c)s<=[c]чтобы сохранить байт.
xnor
5

Perl, 22 байта

21 байт код + 1 для -p.

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

использование

perl -pe 's/./$&x(2>${$&}++)/ge' <<< 'aaabcbccdbabdcd'
aabcbcdd
Дом Гастингс
источник
5

C 57 байт

Вызов f()со строкой, чтобы detriplicate. Функция изменяет свой параметр. Требуется C99 из-за forобъявления -loop.

f(char*p){for(char*s=p,m[256]={0};*s=*p;s+=++m[*p++]<3);}
owacoder
источник
Не могли бы вы поместить объявление sв первом утверждении for?
Мартин Эндер
В С99 можно. Я просто не сделал этого, потому что мне нравится поддерживать совместимость с C89.
owacoder
5

JavaScript (ES6), 35 байт

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

Принимает массив символов в качестве входных данных и возвращает детрицированный массив.

CPU1
источник
Ницца. Вы могли бы сделать, c=>(s[c]=-~s[c])<3чтобы сохранить несколько байтов.
ETHproductions
Я пропустил, что вы можете использовать массивы в качестве входных данных и написал функцию с использованием map. Гольф это выглядело по сути как ваше. Основным отличием было назначение, которое, если вы переключите его, сэкономит несколько байтов. Попробуйте s.filter(c=>(s[c]=s[c]+1|0)<3)33 байта. EDIT: Упс, пропустил комментарий выше меня, что даже лучше :)
Jan
4

PowerShell v2 +, 31 байт

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

Использует то же регулярное выражение, что и в ответе Коби на Retina , только что заключенное в -replaceоператор PowerShell . Работает, потому что оба используют регулярное выражение .NET-flavor в фоновом режиме.

Альтернативно, без регулярных выражений, 56 байтов

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

Создает вспомогательный массив, $bпредварительно заполненный 0s. Приводит входную строку$args[0] как char-array, направляет ее через цикл |%{...}. Каждая итерация выводит текущий символ $_в виде строки, "$_"умноженной на логическое значение, которое только $TRUE(неявно приведено 1здесь), если соответствующая точка в массиве помощников меньше 2(т. Е. Мы еще не видели этот символ дважды). Результирующий набор строк инкапсулируется в скобках и редактируется -joinвместе, образуя единую выходную строку. Это осталось на конвейере и вывод неявный.

AdmBorkBork
источник
регулярное выражение непобедимо. :) Я beleave хэш - таблица лучше тогда массив для варианта без регулярного выражения: $b=@{};-join($args|% t*y|?{++$b.$_-lt3}).
Маззи
1
@mazzy Для варианта без регулярных выражений и вашего кода это должна быть более новая версия, чем PowerShell 2. В результате, я думаю, я оставлю этот ответ без изменений. Вы можете опубликовать свой код как отдельный ответ, хотя!
AdmBorkBork
появилась ли хеш-таблица в версии 3.0? Хорошо. Спасибо.
Маззи
4

Mathematica, 39 байт

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

Анонимная функция. Принимает список символов в качестве входных данных и возвращает список с удаленным дублированием в качестве выходных данных. Использует метод сворачивания по списку и отклонения трехкратных элементов, это не слишком сложно.

LegionMammal978
источник
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.*)

Проверьте все контрольные примеры. ( %Включает режим для каждой линии)

Использует новый этап «Дедупликация», чтобы сэкономить пару байтов при подходе Коби . Дедупликация собирает список всех совпадений с регулярным выражением и заменяет все, кроме первого, пустой строкой. Регулярное выражение соответствует символу, который уже появляется в строке один раз, что означает, что первые два будут сохранены.

FryAmTheEggman
источник
3

К, 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 доступен для бесплатного скачивания ; К6 находится в разработке . Если вы скачали KDB, вы можете войти в K с обратной косой чертой .

Может быть легче увидеть это разбитым на части, но сначала немного синтаксиса: g:xустанавливает gв x. {x+1}это функция, которая принимает аргумент х . В K первый аргумент функции x(второй, yа третийz . Четвертый не нужен).

В настоящее время:

x:"aaabcbccdbabdcd"

=xозначает группу х , которая производит:

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

2#'означает два взятых (от) каждого, который производит

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

Как видите, это смещения первых двух совпадений каждого символа. 2 может быть обобщен.

,/означает присоединиться к каждому и часто называется никак . Это даст нам только значения нашего словаря. Таким образом, ,/"abcd"!(0 1;3 5;4 6;8 12)производит:

0 1 3 5 4 6 8 12

который нам нужно отсортировать. {x@<x}@это идиома, которую часто видят программисты K (Q называет это asc ), где написано « х» в классе х . Разбивая его на части:

  <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 нет этой «амбивалентности».

geocar
источник
Добро пожаловать в PPCG! Отличный первый ответ. :)
Мартин Эндер
У меня есть пара вопросов. 1. Является ли K4 тем же языком, на который вы ссылаетесь (Q / kdb +)? 2. Не могли бы вы показать, как вызывать вашу функцию на входе или как элементы в testVectors.txt должны быть отформатированы?
Деннис
@ Денис 1. Да. Нажмите обратную косую черту, чтобы перейти от Q к K. 2. Как g"aaabcbccdbabdcd"
показано
Хорошо спасибо. Не удалось заставить файловую часть работать, но g"..."она добилась цели. К сожалению, ваш код возвращается aabbccдля ввода abc.
Деннис
@ Денис Вы, возможно, сделали что-то не так: {x{?x@<x}@,/2#'=x}"abc"определенно возвращается "abc". Он вернулся "aabbcc"бы, если бы вы пропустили ?отличное.
геокар
2

Python 2, 51 байт

f=lambda s:s and f(s[:-1])+s[-1]*(s.count(s[-1])<3)

Проверьте это на Ideone .

Деннис
источник
2

Java 8 лямбда, 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, символ не будет добавлен в строку результата. Очень легко, очень коротко;)

Frozn
источник
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 ... Так что да, это место перед <необходимостью. Это %.{}анонимный хеш).

Вен
источник
24 байта
Джо Кинг,
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
12Me21
источник
Добро пожаловать в PPCG! Хороший первый пост!
Rɪᴋᴇʀ
1

Common 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)
CoreDump
источник
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)
Chromozorz
источник
1

К , 27 байт

    f:{x{x@<x}@,/{?2#&x}'x~'/:?x}
    testList:("xxxxx";"abcabc";"abcdabcaba";"abacbadcba";"aaabcbccdbabdcd")
    f'testList
("xx";"abcabc";"abcdabc";"abacbdc";"aabcbcdd")
Chromozorz
источник
1

Руби , 79 62 57 байт

Это довольно громоздко, но я не уверен, что могу играть в гольф намного лучше в данный момент. Любые предложения по игре в гольф приветствуются. Попробуйте онлайн!

Редактировать: -17 байт благодаря Value Ink, предлагая более удачный способ удаления повторяющихся символов. -5 байт от удаления .uniqметода.

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

Ungolfed:

def g(s)
 s.chars.each do |a|
  while s.count(a) > 2
   i = s.rindex(a)
   s[i] = ""
  end
 end
 return s
end
Sherlock9
источник
62 байта:->s{s.chars.uniq.map{|a|s[s.rindex a]=""while s.count(a)>2};s}
Значение Ink
1

JavaScript, 30 байт

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

Используя метод, который @ edc65 предложил для подсчета, но с фильтром массива. При первом появлении символа значение объекта получает «неопределенный» плюс символ (то есть «неопределенный»). В следующий раз значение объекта станет «undefinedxx».

После этого v [x] [11] возвращает значение true, а в сочетании с оператором not значение false, означающее, что символы, которые уже появились дважды, будет отфильтровано.

Grax32
источник
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/

Объяснение кода: метод принимает строку, библиотека анализирует ее как массив символов, а предложение Where представляет собой сложный фильтрующий предикат, который проверяет хэш-карту 'a' на наличие текущего символа. Если существует, счетчик приращения, иначе установлен в 1. Если <2, предикат (и текущий символ) проходит, иначе ошибка

введите описание изображения здесь

applejacks01
источник
Вы можете избежать с помощью returnно сделать ваши функции , разделенных запятыми список из выражений в скобках: n=>(a={},_From(n)....). Последнее выражение является возвращаемым значением. В вашей Whereфункции, вы можете устранить промежуточный bполностью путем сравнения с результатом задания или прироста: x=>(a[x]?a[x]++:a[x]=1)<2.
Апсиллеры
Наконец, вы можете не использовать внешнюю библиотеку на всех (и сохранить байты) , используя строку-сплит многоточие и filterс join: [...n].filter(...).join(""). Отразить истинную / ложную логику при переходе Whereна filter.
Апсиллеры
Ааа хорошие наблюдения! Позже я рассмотрю ваше предложение
поближе
0

Clojure, 72 байта

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

Так много байтов ...

NikoNyrh
источник
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.
AlexRacer
источник