Сокращать массив


26

Цель:

Учитывая массив строк, создайте сокращенные версии каждой строки.

Спецификация:

Для этой задачи аббревиатура - это первые N символов строки. Для строки abc: a, abи abcвсе действительные сокращения, в то время bc, и acнет.

Учитывая массив строк, мы хотим найти кратчайший набор аббревиатур, чтобы, учитывая ввод и любую аббревиатуру, вы могли определить, на какой элемент ввода ссылалась аббревиатура.

Пример:

Входные данные: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

Мы проходим через струны, начиная с первой.

  • Понедельник - это только строка элемента со знаком M, поэтому самое короткое из возможных сокращений M.

  • Вторник начинается с Tчетверга. Это означает, что мы пробуем строку TU. Поскольку никакие другие строки не начинаются с этого, мы используем TU.

  • Среда W, четверг Thи пятница F.

Больше примеров:

Input: "one,two,three,four,five,six,seven"
Output: "o,tw,th,fo,fi,si,se"

Input: "red,orange,yellow,green,blue,purple"
Output: "r,o,y,g,b,p"

Input: "a,ab,abc"
Output: Not valid! No abbreviation for `a` that doesn't apply to the other items.

Заметки:

  • Вы делаете ввод и вывод любым разумным способом.

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

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

  • Строки будут состоять только из печатных ASCII (или печатных символов в вашей кодировке)

  • Это кодовый гольф, поэтому выигрывает меньшее количество байтов!


Связанные: 1 , 2 , 3
Sp3000

5
Возможный дубликат имен пользователей Golf Down the PPCG
Okx

2
Я не думаю, что это дубликат любого из них (хотя все они довольно похожи). На самом деле, я думаю, что это, вероятно, лучший вызов среди четырех; у других есть варианты, которые делают их излишне сложными.

2
Важен ли случай? В частности, ваш пример дня недели использует заглавную Uбукву hдля вторника, но строчную букву для четверга.
Брайан Дж

1
@Mego Не редактируйте мой пост, если модератор не
пометит

Ответы:


10

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

!ms`^(.+?)(?!.+^\1)(?<!^\1.+)

Вход и выход представляют собой разделенные строкой списки строк.

Попробуйте онлайн! (Тестовый набор с разделением запятыми для удобства.)

объяснение

Это просто сопоставляет все префиксы с одним регулярным выражением и печатает их ( !). mи sявляются обычными модификаторами регулярных выражений для создания ^начала .строки соответствия и соответствия строки перевода.

^(.+?)      # Match the shortest possible prefix of a line and capture
            # it in group 1.
(?!.+^\1)   # Make sure that this prefix does not show up in a line after
            # the current one.
(?<!^\1.+)  # Make sure that this prefix does not show up in a line before
            # the current one.

10

Python 2 , 87 86 байт

lambda a:[b[:min(i for i in range(len(b))if sum(s[:i]==b[:i]for s in a)<2)]for b in a]

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


lambda a:[[b[:i]for i in range(len(b))if sum(s[:i]==b[:i]for s in a)<2][0]for b in a]для 85 байтов
Кертис Бехтель

замена len(b)на 4**8экономит еще 2 байта, предполагая, что строки будут не длиннее 65536 символов
Кертис Бектел

8

JavaScript (ES6), 81 78 74 70 байт

Принимает ввод как массив строк.

a=>a.map(s=>[...s].reduce((y,c)=>a.some(x=>x!=s&!x.indexOf(y))?y+c:y))

Отформатировано и прокомментировано

a =>                          // given an array of strings 'a'
  a.map(s =>                  // for each string 's' in 'a':
    [...s].reduce((y, c) =>   //   starting with 'y' = first character of 's',
                              //   for each subsequent character 'c' of 's':
      a.some(x =>             //     if we find a string 'x' in 'a' such that:
        x != s &              //       - 'x' is different from 's'
        !x.indexOf(y)         //       - and 'y' appears at the beginning of 'x'
      ) ?                     //     then:
        y + c                 //       append 'c' to 'y'
      :                       //     else:
        y                     //       keep 'y' unchanged
    )                         //   end of reduce(): returns the correct prefix
  )                           // end of map()

Контрольные примеры


1
70 тоже, но совсем другое: codegolf.stackexchange.com/a/113270/32091
Qwertiy

+1 за reduce.
Нил

6

Желе , 14 байт

;\w@þ=1Si1⁸ḣð€

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

Как это работает

;\w@þ=1Si1⁸ḣð€  Monadic link. Argument: A (string array)

            ð   Collect all links to the left into a chain (arity unknown) and
                begin a dyadic chain.
             €  Map the previous chain over A. The current chain is dyadic and the
                mapped one inherits its arity. Thus, the right will be A for all
                invocations, while the left argument will iterate over A.
                For each string s in A, the following happens.
;\                Cumulative reduce by concatenation; yield all prefixes of s.
  w@þ             Window index swapped table; for each string t in A and each
                  prefix p of s, find the index of the substring t in p.
                  The first index is 1; 0 means not found.
     =1           Compare the indices with 1, returning 1 iff t begins with p.
       S          Sum the Booleans across columns, counting the number of strings
                  in A that begin with a given prefix.
        i1        Find the first index of 1, the shortest prefix that is unique
                  across all strings in A.
          ⁸       Head; truncate s to the computed length.

6

Haskell , 48 байтов

[_]#x=""
a#(c:y)=c:[z|d:z<-a,c==d]#y
f=map=<<(#)

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

  • fявляется основной функцией, беря список Strings и возвращая a String. Его определение является монадическим сокращением для f a=map (a#) a.
  • a#xсмотрит на строку xи список aи пытается найти кратчайший префикс, xкоторый уникален в a. Если aесть единственный элемент, просто используйте пустую строку. Если aэто еще не один элемент, отрежьте первый символ x, отфильтруйте и обрежьте элементы, aначинающиеся с того же символа, а затем выполните повторение.


3

Желе , 14 12 байт

ḣ€JṙLḶ$ḟ/€Ḣ€

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

Как это работает

ḣ€JṙLḶ$ḟ/€Ḣ€  Main link. Argument: A (string array)

  J           Yield the 1-based indices of A, i.e., [1, ..., len(A)].
ḣ€            Head each; for each string s in A, take the first 1, ..., and len(A) 
              characters. This builds the 2D array of prefixes of all strings in A.
    LḶ$       Length-unlength; yield [0, ..., len(A)-1].
   ṙ          Rotate the 2D array 0, ..., and len(A)-1 units to the left.
       ḟ/€    Reduce filterfalse each; for each rotation, remove all prefixes from
              the first set that also occur in later sets.
          Ḣ€  Head each; for each rotation, keep only the shortest unique prefix.

Просто интересно, почему у вас есть 2 ответа здесь? Я люблю их обоих, но мне просто интересно, почему у вас есть два ответа Jelly здесь. :)
HyperNeutrino

Если у меня есть два одинаково конкурентных подхода, но достаточно разные подходы, я обычно публикую их в отдельных ответах.
Деннис

Хорошая точка зрения. Да, мне просто интересно. :) Это хорошая идея; У меня обычно не более одного подхода: P
HyperNeutrino

2

C ++ 11 (MinGW), 198 байт

#import<list>
#import<iostream>
f(std::list<std::string>l){int i,m;for(auto s:l){for(i=0,m=1;++i<s.length();)for(auto t:l)if(t!=s&&t.substr(0,i)==s.substr(0,i))m=i+1;std::cout<<s.substr(0,m)<<" ";}}

Звоните с:

int main()
{
    f({"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"});
}

Добавление voidидентификатора перед функцией должно заставить ее компилироваться и на других компиляторах, тем самым добавляя 5 байтов к длине.


Должно быть void f..., иначе не работает ... + 5 байт, к сожалению. Для функций, насколько я знаю, нужны спецификаторы типов в C ++
г-н Xcoder

Кроме того, отличный подход! Гольф в C / C ++ может быть болезненным
Mr. Xcoder

@ Mr.Xcoder Он компилируется на компиляторе MinGW, который я использую. Так что это либо расширение компилятора, либо неопределенное поведение.
Steadybox

Я думаю, что речь идет о расширении компилятора, в GCC это не работает ...
Mr. Xcoder

1
Пока существует среда, в которой работает код, он действителен
подземный

2

Javascript ES6, 70 символов

s=>(s+'#'+s).replace(/(\w+?)(\w*)(?=(\W(?!\1(?!\2))\w+)+$)|#.+/g,"$1")

f=s=>(s+'#'+s).replace(/(\w+?)(\w*)(?=(\W(?!\1(?!\2))\w+)+$)|#.+/g,"$1")

console.log(f("one,two,three,four,five,six,seven")==="o,tw,th,fo,fi,si,se")
console.log(f("red,orange,yellow,green,blue,purple")==="r,o,y,g,b,p")
console.log(f("one,two,three,four,five,six,seven".split`,`)==="o,tw,th,fo,fi,si,se")
console.log(f("red,orange,yellow,green,blue,purple".split`,`)==="r,o,y,g,b,p")


2

PHP, 131 120 119 118 байт

Спасибо @ Йорг за preg_grep.

for(;a&$s=$argv[++$k];$i=+$t=!print"$t
")for(;a&$s[$i]&&1<count(preg_grep("(^".preg_quote($t.=$s[$i++]).")",$argv)););

принимает входные данные из аргументов командной строки; выводит результаты по одной строке каждая.
Запустите -nrили попробуйте онлайн .

  • может потерпеть неудачу , если вход содержит ничего , начиная с -.
    +15 байт для исправления: заменить второй $argvна array_slice($argv,1).
  • выдает предупреждения в PHP 7.1; заменить a&на ""<(+1 байт), чтобы исправить.
  • -12 байт, если входные данные не содержат специальных символов регулярного выражения:
    вставить &($t.=$c)перед &&и заменить ". preg_quote($t.=$c)."на $t.

сломать

for(;a&$s=$argv[++$k];      # loop $s through arguments
    $i=+$t=!                # 3. reset $i and $t to empty
    print"$t\n")            # 2. print abbreviation
    for(;a&($c=$s[$i++])    # 1. loop $c through characters
        &&1<count(              # 3. if count==1, break loop
            preg_grep("(^"      # 2. find matching arguments
                . preg_quote(
                $t.=$c          # 1. append $c to abbreviation
            ).")",$argv)
        );
    );

версия без регулярных выражений, 131 130 байт

for($a=$argv;a&$s=$a[++$k];$i=+$t=!print"$t
")for($n=1;$n&&a&$c=$s[$i++];)for($n=$m=1,$t.=$c;a&$u=$a[$m++];)$n-=0===strpos($u,$t);

Замените первое и последнее a&на ""<(+2 байта) для исправления в PHP 7.1.

сломать

for($a=$argv;a&$s=$a[++$k];     # loop through arguments
    $i=+$t=!print"$t\n")            # 2. print abbreviation, reset $i and $t to empty
    for($n=1;$n&&a&$c=$s[$i++];)    # 1. loop through characters while $n<>0
        for($n=$m=1,                    # reset $n and $m to 1
            $t.=$c;                     # append current character to prefix
            a&$u=$a[$m++];              # loop through arguments:
        )$n-=0===strpos($u,$t);         # -$n = number of matching strings -1

совершенно неинтересная заметка:
strstr($u,$t)==$uи 0===strpos($u,$t)имеют одинаковую длину и одинаковый результат.


Используйте реальный символ новой строки ( 0x0A) вместо \n, он сохранит один байт;).
Blackhole

@ Blackhole Спасибо; Я забыл об этом на этот раз.
Титус

1

PHP, 127 байт

работает не с недействительными массивами

<?foreach($a=$_GET as$k=>$v)for($i=0,$c=2,$s="";$c>1;$r[$k]=$s)$c=count(preg_grep("_^".($s.=$v[$i++])._,$a));echo join(",",$r);

PHP, 132 байта

<?foreach($a=$_GET as$v)for($i=0,$s="";a&$v[$i];)if(count(preg_grep("_^".($s.=$v[$i++])._,$a))==1){$r[]=$s;break;}echo join(",",$r);

Онлайн версия

151 байт поддерживает специальные символы

<?foreach($a=$_GET as$v)for($i=0,$s="";a&$v[$i];)if(count(preg_grep("_^".preg_quote($s=substr($v,0,++$i),_)._,$a))==1){$r[]=$s;break;}echo join(",",$r);

PHP, 140 байт

<?foreach($a=$_GET as$k=>$v)for($i=0;a&$v[$i];)if(count(preg_grep("#^".($s=substr($v,0,++$i))."#",$a))==1){$r[]=$s;break;}echo join(",",$r);

Это не удастся, если входные данные содержат специальные символы регулярных выражений. У меня было бы 113 байтов вместо 131, если нет.
Титус

@Titus В этом случае я мог бы добавить preg_quoteMake только на 10 байт больше
Йорг Хюльсерманн

Также произойдет сбой, если вход содержит 0. Но вы можете сохранить один байт с помощью $i=+$s="".
Титус

и вы можете удалить count()-count()материал: ввод гарантированно будет действительным (-21 байт). Я думаю, что я мог бы исправить и гольф это до 120 байтов. $_GETбыла хорошая идея!
Титус

@ Я не понял, что разрешены только допустимые массивы. Да, он потерпит неудачу, если строка содержит ноль, но это
породило

0

Clojure, 118 байт

#(reduce(partial map(fn[a b](or a b)))(for[i(range 1e2)S[(for[c %](take i c))]](for[s S](if(=((frequencies S)s)1)s))))

Это работает с префиксами вплоть до длины, 1e2но тот же счетчик байтов может поддерживать до 1e9. iзацикливает длины префиксов, Sявляется последовательностью подстрок длины i. Последнийfor заменяет те подстроки, с nilкоторыми встречаются чаще, чем один раз. Сокращение сохраняет первое ненулевое значение для каждой строки, слишком плохо, orэто не функция, поэтому мне пришлось обернуть ее.

Это на самом деле возвращает списки списков символов, как ((\M) (\T \u) (\W) (\T \h) (\F)), но я думаю, что это приемлемо. Clojure довольно многословен со строками, иsubs бросил бы в StringIndexOutOfBoundsExceptionотличие от take.

Полные примеры:

(def f #(reduce(partial map(fn[a b](or a b)))(for[i(range 1e2)S[(for[c %](take i c))]](for[s S](if(=((frequencies S)s)1)s)))))

(f ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"])
(f (re-seq #"[^,]+" "one,two,three,four,five,six,seven"))
(f (re-seq #"[^,]+" "red,orange,yellow,green,blue,purple"))

0

SQL (версия PostgreSQL 9.4), 219 байт

Теперь для самого длинного ответа :) Я не думаю, что это могло бы даже победить Java. Я постараюсь побриться еще немного. Надеюсь избавиться от одного из вложенных запросов, но мне не нравятся мои шансы.
Это предполагает, что есть таблица, которая содержит строки для работы. Поскольку это SQL, порядок возврата не гарантируется таким же, как порядок таблиц, и в этом случае маловероятен. Если это проблема, я буду удалять.

SELECT R FROM(SELECT*,RANK()OVER(PARTITION BY A ORDER BY C,N)Z FROM(SELECT*,SUM(1)OVER(PARTITION BY R)C FROM(SELECT*FROM A JOIN LATERAL(select left(A,n)R,N FROM generate_series(1,length(A))S(n))L ON 1=1)X)Y)Z WHERE Z=1

SQL Fiddle
Объяснение

  SELECT *
  FROM A 
    JOIN LATERAL(SELECT LEFT(A,n)R,N 
    FROM generate_series(1,length(A))S(n))L ON 1=1

Самый внутренний запрос использует generate_seriesи LATERALсоединение для создания строк для строки, разбитой на увеличивающиеся длины, поэтому «one» становится «o», «on», «one». Количество символов в ответе также сохраняется.

SELECT 
  *,
  SUM(1)OVER(PARTITION BY R)C
FROM ( ... )X

Затем мы добавляем количество записей, которые имеют одинаковый результат. Например, «f» из четырех и пяти имеет 2, но «fo» и «fi» имеют по одному. OVERЗаявление в SQL может быть довольно мощным. COUNT(*)было бы обычным способом, но SUM(1)дает тот же результат.

SELECT 
  *,
  RANK()OVER(PARTITION BY A ORDER BY C,N)Z
FROM ( ... )Y

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

SELECT R FROM ( ... )Z WHERE Z=1;

Наконец, мы выбираем самый низкий номер ранга для каждого слова.



0

APL (Dyalog) , 27 байтов

{⍵↑¨⍨1⍳⍨¨↓+/(↑,⍵)∘.(⊃⍷)⍵}

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

{ анонимная функция, где ⍵ представляет аргумент ...

∘.( таблица функций, где функция

   первый элемент

   логический список «левый аргумент начинается здесь с правого аргумента?»

) где правильные аргументы

 аргументы

( и левый аргумент

   таблица со строками, состоящая из

  ,/ префиксы

  ¨ каждый из

   аргументы

+/ сумма через (подсчитывает, сколько аргументов передается с этим префиксом)

 разбить таблицу на список строк

⍳⍨¨ в каждом найти местоположение первого

1 один (то есть первый префикс, который возглавляет только один аргумент)

↑¨⍨ для каждого местоположения, принимает столько символов из соответствующего элемента

 Аргумент

} конец анонимной функции


0

PowerShell, 151 139 байт

$x,$w=@(),$args[0];$w|%{$k=$_;$a='';foreach($l in [char[]]$k){$a+=$l;if($a-notin$x-and!($w|?{$_-ne$k-and$_-like"$a*"})){$x+=$a;break;}}};$x

Интересно, есть ли лучший способ сделать это. Пришлось использовать foreach(над a |%), чтобы иметь возможность выполнять breakв вложенном цикле, не помечая его.

Редактировать: 2 гольфа от AdmBorkBork


1
Я не прошел через код напрямую, но наверняка вы могли бы использовать -notinвместо -not$x.contains($a)и !($w...вместо того, -not($w...чтобы сохранить несколько байтов, да?
AdmBorkBork

0

APL, 26 байт

{⍵↑¨⍨1+⌈/+/¨∘.(∧\=∧≢)⍨↓↑⍵}

Объяснение:

  • ↓↑⍵: добавьте каждую строку, чтобы она соответствовала длине самой длинной строки
  • ∘.(... )⍨: для каждой возможной пары строк найдите общий префикс:
    • : неравенство массива
    • : а также
    • =: поэлементное равенство
    • ∧\: and-scan (сохраняются только первые совпадения)
  • +/¨: суммировать каждый вектор в таблице, давая длину общих префиксов
  • ⌈/: найти максимальное значение в каждом столбце
  • 1+: добавить один, давая количество символов, необходимое для сохранения уникальности каждой строки
  • ⍵↑¨⍨: взять столько символов из каждой строки

Тест:

      {⍵↑¨⍨1+⌈/+/¨∘.(∧\=∧≢)⍨↓↑⍵}'Monday' 'Tuesday' 'Wednesday' 'Thursday' 'Friday'
┌─┬──┬─┬──┬─┐
│M│Tu│W│Th│F│
└─┴──┴─┴──┴─┘
      {⍵↑¨⍨1+⌈/+/¨∘.(∧\=∧≢)⍨↓↑⍵}'one' 'two' 'three' 'four' 'five' 'six' 'seven'
┌─┬──┬──┬──┬──┬──┬──┐
│o│tw│th│fo│fi│si│se│
└─┴──┴──┴──┴──┴──┴──┘
      {⍵↑¨⍨1+⌈/+/¨∘.(∧\=∧≢)⍨↓↑⍵}'red' 'orange' 'yellow' 'green' 'blue' 'purple'
┌─┬─┬─┬─┬─┬─┐
│r│o│y│g│b│p│
└─┴─┴─┴─┴─┴─┘

0

Q, 93 байта

{n:1;{$[any e:(,/)1<{(+/)i like x}each i:z#'x;[z+:1;y:?[e;z#'x;i];.z.s[x;y;z]];y]}[x;n#'x;n]}

Решается рекурсивно, принимает строку в качестве входных данных, получает первые n элементов каждой строки с каждой рекурсией. Если какой-либо из этих элементов не является уникальным, он заменяет их первыми n + 1 элементами.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.