Уникальный дешево


93

Напишите функцию или программу, которая определяет стоимость данной строки, где

  • стоимость каждого символа равна количеству повторений символа до этой точки в строке, и
  • стоимость строки - это сумма затрат ее символов.

пример

Для ввода abaacabстоимость рассчитывается следующим образом:

a b a a c a b
1   2 3   4    occurrence of a
  1         2  occurrence of b
        1      occurrence of c
1+1+2+3+1+4+2 = 14

Таким образом, стоимость строки abaacabсоставляет 14.

правила

  • Оценка вашего представления - это стоимость вашего кода, как определено выше , то есть ваше представление выполняется с использованием собственного исходного кода, причем более низкий показатель лучше.
  • Ваше представление должно работать со строками, содержащими печатные символы ASCII, а также все символы, используемые в вашем представлении.
  • Символы чувствительны к регистру, то есть aи Aявляются разными символами.

Testcases

input -> output
"abaacab" -> 14
"Programming Puzzles & Code Golf" -> 47
"" -> 0
"       " -> 28
"abcdefg" -> 7
"aA" -> 2

Leaderboard


2
Как программные флаги, такие как -nPerl, учитываются в счете? Традиционно он считается как 1 байт, потому что расстояние редактирования между стандартом perl -eи perl -ne1 равно 1, но будет ли для этой задачи nсчет для подсчета дубликатов?
Value Ink

2
@ValueInk Да, я считаю, что подсчет nявляется наиболее справедливым вариантом.
Лайкони

1
Я действительно хотел бы найти решение этой проблемы.
Peter1807

10
+1 для Оценка вашего представления является стоимость вашего кода
luizfzs

1
стоимость персонажа определяется как how often this character has already occurred in the string, я бы, вероятно, изменил на, how many times the character has occurred up to this pointчтобы было яснее, что первое использование стоит 1, а не 0
подземный

Ответы:


83

MATL , оценка 4

&=Rz

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

объяснение

Рассмотрим ввод 'ABBA'в качестве примера.

&=   % Implicit input. Matrix of all equality comparisons
     % STACK: [1 0 0 1;
               0 1 1 0;
               0 1 1 0;
               1 0 0 1]
R    % Upper triangular part
     % STACK: [1 0 0 1;
               0 1 1 0;
               0 0 1 0;
               0 0 0 1]
z    % Number of nonzeros. Implicitly display
     % STACK: 6

14
Вы профессор линейной алгебры?
Волшебная Урна Осьминога

4
@carusocomputing На самом деле профессор мобильной связи. Моя склонность к использованию матриц исходит из многолетнего программирования в Matlab
Луис Мендо

Ухоженная! Matlab большой в этой области? Я никогда не смотрел на GSM или что-то подобное.
Волшебная Урна Осьминога

2
Я присоединился к этому сообществу, чтобы поблагодарить вас за это блестящее решение!
Wboy

1
@carusocomputing Matlab - очень распространенный инструмент / язык в разработке в целом. Это хорошо для численных расчетов: линейная алгебра, обработка сигналов и тому подобное. И, будучи
Луис Мендо

17

Питон , оценка 49

lambda S:sum(1+S.count(C)for[C]in	S)/2

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

Там есть вкладка после in.

Распределение баллов:

  • +27 за 27 уникальных персонажей
  • +16 за 8 двойных символов: ()Camnou
  • +6 за 1 утроенный символ: S

13
Используйте вкладку вместо пробела для сохранения байта.
mbomb007

1
@ mbomb007 Просто была та же идея :-)
xnor

1
@ mbomb007 Ха, это гениальный трюк :-)
ETHproductions

14
@ mbomb007, это всего лишь война против табуляции и пробелы в коде игры в гольф
Эрик Игрок в гольф

2
Я собирался предложить использовать фид форм (который также допускает пробелы в синтаксисе Python), но у вас больше нет пробелов для замены.
user2357112

8

T-SQL, оценка 775 579! 580

declaRe @ char(876),@x int,@v int=0Select @=q+CHAR(9)from z X:seleCT @x=len(@),@=REPLACE(@,LEFT(@,1),''),@v+=(@x-LEN(@))*(@x-LEN(@)+1)/2IF LEN(@)>0GOTO X prINT @v-1

РЕДАКТИРОВАТЬ : отбросил пару переменных, немного сжаты. Сокращение до 16 @символов вместо 22, что само по себе уменьшает мой счет на целых 117 очков!

Хороший конкурс, мне нравится требование оптимизировать что-то помимо общего количества символов.

Ввод осуществляется с VARCHAR поля д в уже существующей таблице г , в соответствии с нашими правилами ввода - вывода . База данных, содержащая эту входную таблицу, должна быть настроена на регистр с учетом регистра .

отформатирован:

declaRe @ char(876), @x int, @v int=0
Select @=q+CHAR(9)from z
X:
    seleCT @x=len(@)
          ,@=REPLACE(@,LEFT(@,1),'')
          ,@v+=(@x-LEN(@))*(@x-LEN(@)+1)/2
IF LEN(@)>0 GOTO X
prINT @v-1

Ключевые слова SQL не чувствительны к регистру, поэтому я использовал смешанный регистр, чтобы минимизировать количество повторяющихся букв ( aaAA генерирует лучший / более низкий балл, чем aaaa ).

Основной цикл сравнивает длину до и после удаления всех экземпляров первого символа. Эта разница n * (n + 1) / 2 добавляется к промежуточному итогу.

Функция SQL LEN()досадно игнорирует завершающие пробелы, поэтому мне пришлось добавить управляющий символ и вычесть 1 в конце.

РЕДАКТИРОВАТЬ : Исправлена ​​ошибка в моем собственном счете на 2 балла (проблема с цитатами), уменьшена на 1 путем изменения регистра одного R. Также работая над совершенно другой стратегией, я опубликую это как собственный ответ.


3
Сначала я думал, что ваш счет был579! ≈ 8.22 x 10^1349
инженер Тост

8

C (gcc) , оценка:  113  103 100   96  91

Спасибо @ugoren, @CalculatorFeline, @gastropner, @ l4m2 и @ JS1 за их советы.

g(char*s){int y[238]={};while(*s)*y-=--y[*s++];*y/=1;}

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

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


3
Предложение: Используйте имена переменных, которые не используются в ключевых словах, как z, x, c.
CalculatorFeline

@CalculatorFeline charвключает в себя c...
Нил

3
Кроме того, вам нужен только массив из 127 элементов ( \x7fне для печати), и, пожалуйста, добавьте пояснение.
CalculatorFeline

1
Поздно на вечеринку, но это должно быть 96:z;g(char*s){int y[238]={z=0};while(*s)z+=--y[*s++];z/=~0;}
гастропнер

1
g(char*s){int y[238]={};while(*s)*y+=--y[*s++];*y/=~0;}
l4m2

7

JavaScript (ES6), оценка 81 78

Сэкономили 3 балла благодаря @Arnauld

s=>s.replace(d=/./g,z=>q+=d[z]=-~d[z],q=0)&&q

Мое оригинальное рекурсивное решение Score-81:

f=([c,...s],d={})=>c?(d[c]=-~d[c])+f(s,d):0



7

Сетчатка , оценка 34

s(O`.
M&!`^|(?<=(.))\1*
.

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

объяснение

s(O`.

Мы начнем с сортировки всех символов на входе, чтобы идентичные символы были сгруппированы в один прогон. s(Активирует SingleLine режим для всех стадий (т.е. делает .матч перевода строки).

M&!s`^|(?<=(.))\1*

Цель состоит в том, чтобы превратить серию из n символов в T n символов ( n- е треугольное число), потому что это количество вхождений этого символа. Для этого мы найдем перекрывающиеся совпадения. В частности, для каждого i в [1, n] мы собираемся включить в совпадение символы i-1 . Мы получаем все эти совпадения из-за перекрывающегося флага &. Это дает нам n * (n-1) / 2 = T n-1 = T n - n символов только из совпадений. Но стадия совпадения объединит их с переводами строки, которые являются n переводами строки для nСпички. Есть только одна проблема. После последнего совпадения не будет перевода строки, поэтому общее количество символов в выводе на один меньше, чем нам нужно. Мы исправляем это, также сопоставляя начало ввода, что дает нам один ведущий перевод строки, если есть хотя бы одно другое совпадение.

.

Наконец, мы просто посчитаем, сколько символов в строке.


6

Хаскелл, оценка 52 51

f(a:b)=1+sum[1|c<-b,c==a]+f b;f _=0

Там есть вкладка между fи _.

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

Значение пустой строки равно 0. Значение строки s, где aпервый символ, а bостальная часть строки - 1 плюс вхождения ain bплюс рекурсивный вызов с b.


5

J , оценка 16

1#.,@(*+/\"1)&=

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

объяснение

1#.,@(*+/\"1)&=
              =  Self-classify: bit matrix of equality between input
                 and its unique elements.
     (      )&   Apply verb in parentheses to it:
       +/\         running sums
          "1       of each row
      *            multiplied with original matrix.
                 This causes the i'th 1 on each row to be replaced by i.
   ,@            Flatten the resulting matrix
1#.              and interpret as a base-1 number, computing its sum.

Использование 1#.вместо +/@суммы сэкономило несколько баллов и &может быть использовано вместо @монадического контекста для сохранения еще одного. Повторение 1стоило мне одного дополнительного очка, но я не смог от него избавиться.


«позже» ждет четверть
CalculatorFeline

2
@CalculatorFeline через 10 часов все еще позже. : P
Zgarb

Давайте сделаем это вторым праздником сейчас.
CalculatorFeline

Я лично использую этот формат для ответов TIO, чтобы отразить точное количество байтов в разделе кода, возможно, вы захотите его использовать
Конор О'Брайен,

5

R , оценка: 67 83 95 128

-61 благодаря лучшим советам от Джузеппе

function(x,y=table(utf8ToInt(x)))y%*%{y+1}/2

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

Строка разбивается с использованием utf8ToIntи подсчитывается каждое значение ascii table. Результат рассчитывается с использованием умножения матрицы %*%на это + 1 и, наконец, наполовину.


использовать tableвместо rle; вы также можете избавиться от sort(и вам не нужно [[1]]strsplit
Джузеппе

@ Giuseppe Большое спасибо. Я даже не думал о столе, скоро включится.
MickyT

2
Я думаю, что вы можете сохранить еще несколько байтов, используя другое имя переменной вместо n(так как оно в functionдва раза), а также изменив (n+1)на{n+1}
Giuseppe

оценка: 67 . Некоторые изменения в этом могут сделать возможным дальнейшее снижение оценки.
Джузеппе

@ Джузеппе ... Я должен был перечитать это. упс
MickyT


4

Пиф , оценка 6

1 байт благодаря isaacg.

+F/V._

Тестирование.

Как это устроено

+F/V._
+F/V._QQ  implicit input
  /V      vectorize count: for each element in the first argument,
                           count the number of occurrences of the
                           second argument:
    ._Q       all prefixes of input
       Q      input
+F        fold (reduce) on +, base case 0.

s+0так же, как +F.
Исаак

Хороший! Лучшее, что я могу сделать, - это usaShHGrScQ1 8Z16. Ты можешь добавить объяснение?
Цифровая травма

1
@DigitalTrauma Я добавил объяснение.
Утренняя монахиня

s/LQОценка 4, использует ли это функции, которые датируют вызов?
Дэйв



4

C, 60 байтов, оценка 108 95

g(char*s){int y[256]={},z=0;while(*s)z-=--y[*s++];return z;}

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

Обычно операторы до и после приращения отлично подходят для код-гольфа, но они действительно больно справляются с этой задачей!

РЕДАКТИРОВАТЬ: вычитая отрицательные числа вместо добавления положительных, я сохранил целую кучу очков. Замена for()с while()устранена точкой с запятой , а также.



3

C # (.NET Core) , оценка ∞ (я имею в виду, 209)

b=>b.Distinct().Select(z=>{var w=b.Count(p=>p==z);return w*(w+1)/2;}).Sum()

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

Оценка включает в себя следующее:

using System.Linq;

Я знаю, что это было давно, но вы можете перейти return w*(w+1)/2к return-~w*w/2(оценка 196). РЕДАКТИРОВАТЬ: Вы можете создать порт моего ответа Java 8 для оценки 149 : using System.Linq;b=>{int[]x=new int[256];return\nb.Select(z=>++x[z]).Sum();} Попробуйте онлайн.
Кевин Круйссен

1
@KevinCruijssen: Я получил ваше решение до 111:b=>{var x=new int[256];return\nb.Sum(z=>++x[z]);}
Разнагул

@raznagul ( * входящий полугодовой ответ * ) 109, если вы измените второй пробел на вкладку. ;) Попробуйте онлайн.
Кевин Круйссен,

1
@KevinCruijssen (еще полугодовой ответ поступает) 49 с интерактивным компилятором, и я думаю, что он никогда не опустится ниже 48. Мне кажется странным, что чем больше ответов C # в гольфе получается, тем более читабельными они всегда кажутся. Попробуйте онлайн!
кто-то

3

Желе , оценка 5

ĠJ€ẎS

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

Спасибо Leaky Nun за -2 (ранее за его ответ )


Аааа, я не заметил этот вопрос достаточно быстро.
Утренняя монахиня

@LeakyNun ps ты не всегда ниндзя, ни кто-либо другой
Эрик Outgolfer

В самом деле? Я так не думаю.
CalculatorFeline


@ LeakyNun Как и обещал ... да, заслуга есть :)
Эрик Outgolfer

3

PowerShell, оценка 64

$z=@{}
$ARGS|% getE*|%{$u+=($Z.$_+=1)};$U

(Оценка основана на новой строке перевода строки, которая не является стандартом Windows, но работает в PS).

PS C:\> D:\unique-is-cheap.ps1 (gc D:\unique-is-cheap.ps1 -raw)
64
  • Счетчик @{}
  • Перебирать буквы; $argsявляется массивом параметров - в этом случае входная строка делает его единым массивом элементов; |%выполняет цикл foreach над элементами и использует getE*ярлык для соответствия GetEnumerator()строковому методу и вызывает его, чтобы превратить строку в поток символов.
  • |%Зацикливайте символы и увеличивайте их в хеш-таблице, добавляйте к промежуточной сумме. ($x+=1)Форма с скобками и изменяет переменную и выводит новое значение для использования.
  • Выведите промежуточный итог.

(Когда я впервые написал его, он был $c=@{};$t=0;[char[]]"$args"|%{$c[$_]++;$t+=$c[$_]};$tсо счетом 128, и я чувствовал, что он не станет намного ниже. Половина его до 64 весьма приятна).


1
61 очко / 38 байт , возиться с приращением
Веска


3

Юлия 0,6 , 45 байт, Оценка: 77

Вдохновленный решением MATL:

f(w)=sum(UpperTriangular([z==j for z=w,j=w]))

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

Менее симпатичное решение, использующее количество:

Юлия 0,6 , оценка: 82

F(w)=sum(l->[l+1]l/2,count(x->x==i,w)for i=Set(w))

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

Спасибо Guiseppe за указание на счет и за подсказки. Эти комментарии помогли мне загрузить.


1
Оценка вашего представления - это стоимость вашего кода , которая, я думаю, составляет 135.
Джузеппе

1
Я не очень хорошо знаю Джулию, но я думаю, что вы можете уменьшить счет до 110 , поменяв несколько переменных и убрав скобки. Если возвращает вектор одного элемента допускается, то вы можете заменить (x+1)с [x+1]целью дальнейшего снижения счет.
Джузеппе

Вы можете сохранить счет, изменив второй пробел на вкладку или новую строку: счет 104 . И @Giuseppe совет использования [x+1]вместо того, (x+1)чтобы снизить его до 98 баллов .
Кевин Круйссен

3

Java 10, оценка: 149 138 137 134 133 130 103 102 101 100

( Байт: 72 73 74 75 64 62 61 ) Байты увеличиваются, но оценка снижается. : D

x->{int j=0,q[]=new int[256];for(var    C:x)j+=++q[C];return
j;}

Оценка -28 (и -11 байт) благодаря @Nevay .
-1 оценка (и -2 байта) благодаря @ OlivierGrégoire .
-1 оценка (и -1 байт) путем преобразования Java 8 в Java 10.

Объяснение:

Попробуй это здесь.

x->{                     // Method with character-array parameter and integer return-type
  int j=0,               //  Result-integer, starting at 0
      q[]=new int[256];  //  Integer-array with 256 times 0
  for(var   C:x)         //  Loop over the characters of the input array
    j+=++q[C];           //   Raise the value in the array by 1,
                         //   and then add it to the result-integer
  return                 //  Return 
  j;}                    //         the result

1
Вы можете удалить, ~если вы используете j=0и return-j;(133).
Неваи,

1
103:x->{int[]q=new int[256];return\nx.chars().map(v->++q[v]).sum();}
Невай

1
@Nevay 103 на самом деле, когда я использую jвместо u( returnсодержит u) и новую строку и табуляцию вместо пробелов. РЕДАКТИРОВАТЬ: Хе-хе, вы редактировали правильно, когда я сделал этот комментарий. :)
Кевин Круйссен

3

F #, оценка 120 118

let j z=Seq.countBy id z|>Seq.sumBy(fun x->List.sum[0..snd x])

-2 спасибо Кевину Круйссену !

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

Принимает stringкак вход. Seq.countByсоединяет каждый отдельный символ с его количеством ( idэто функция идентичности), чтобы вы получили коллекцию, как 'a' = 4, 'b' = 2и т.д.

Seq.sumByБерет отсчета для каждой буквы и суммирует все числа от 0графы для этого письма. Так что если 'a' = 4бы коллекция была бы 0, 1, 2, 3, 4суммированной, то есть 10. Затем Seq.sumByсуммирует все эти суммы.


2
Вы можете уменьшить свой счет на 2, изменив let qна let j, так как qуже используется в обоих Seq.
Кевин Круйссен,

2

APL (Дьялог) , оценка 15

+/1 1⍉+\∘.=⍨⍞

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

 получить текстовый ввод

∘.=⍨ таблица равенства с собой

+\ накопленная сумма по

1 1⍉ диагональ (буквально сворачивает оба измерения в одно измерение)

+/ сумма


2

Сетчатка , оценка 68 45 43

s`(.)(?<=((\1)|.)+)
$#3$*
1

Попробуйте онлайн! Ссылка показывает оценку. Редактирование: Спасибо @MartinEnder, который сохранил 20 байтов, используя перекрывающиеся совпадения вместо заголовков, и еще три байта, сгруппировав этапы так, что sфлаг нужно применять только один раз. Сохраните еще два байта, вычисляя треугольное число по-разному, избегая необходимости сортировки.



2

Perl 5 баллов 91 83

Использует -pфлаг, который добавляет 2 из-за p в split.

$x=$_;$b+=++$a{$_}for(split//,$x);$_=$b

Добро пожаловать в PPCG!
Лайкони

1
Используя ваш ответ в качестве основы и применяя некоторые приемы со страницы советов, мне удалось снизить ваш счет до 31: попробуйте онлайн! , $` is automatically print ed after each call so we can use that to store the score and /./ g` возвращает список всех символов в $_, который дешевле, чем split//.
Дом Гастингс

Я знаю, что это старая проблема, но вы можете сократить счет еще больше: попробуйте онлайн!
Xcali

2

Октава , 39 байт, оценка 69

@(a)sum((b=hist(a,unique(1*a))).^2+b)/2

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

Хотя есть и другой ответ от Octave, этот - полностью мой и другой подход, плюс он набирает меньше очков :).

Подход сводится к тому, чтобы сначала найти количество (b) каждого уникального символа, что достигается с помощью функции гистограммы. Затем для каждого элемента мы вычисляем сумму от 1 до b, что делается по формуле (b*(b+1))/2. Затем отдельные суммы суммируются в итоговый счет.

При тестировании кажется, что скобки действительно дорогостоящие, потому что многие из них необходимы. Я оптимизировал исходную оценку около 88, переставив вопросы, чтобы свести к минимуму количество открытых / закрытых скобок - следовательно, теперь мы делаем / 2 для итоговой суммы, а не по отдельности, а также я изменил формулу, чтобы (b^2+b)/2поскольку это требует меньше скобок.


1
К сожалению, это похоже на ошибку в пустой строке:error: hist: subscript indices must be either positive integers less than 2^31 or logicals
Laikoni

2

Common Lisp, оценка 286 232 222

(loop with w =(fill(make-list 128)0)as z across(read)sum(incf(elt w(char-code z))))

Высокая оценка за счет объемного синтаксиса встроенных операторов Common Lisp.

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

Негольфированный код:

(loop with w = (fill (make-list 128) 0)  ; create a list to count characters
   as z across (read)                   ; for each character of input
   sum (incf (elt w (char-code z))))     ; increase count in list and sum

2

Mathematica, оценка 54

Total[#(#+1)/2&@Counts@Characters@#]&

вход

[ "ABCDEFG"]

благодаря hftf


Total[#(#+1)/2&@Counts@Characters@#]&счет 54.
hftf
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.