Distância da corda

28

Desafio

Dada a entrada de uma seqüência de letras minúsculas [a-z], produza a distância total entre as letras.

Exemplo

Input: golf

Distance from g to o : 8
Distance from o to l : 3
Distance from l to f : 6

Output: 17

Regras

  • Lacunas padrão proibidas
  • Este é o - a resposta mais curta em bytes ganha.
  • O alfabeto pode ser deslocado de qualquer direção. Você sempre deve usar o caminho mais curto. (ou seja, a distância entre xe cé 5).

1

Casos de teste

Input: aa
Output: 0

Input: stack
Output: 18

Input: zaza
Output: 3

Input: valleys
Output: 35
Daniel
fonte

Respostas:

11

Geléia , 11 8 bytes

OIæ%13AS

Economizou 3 bytes graças a @ Martin Ender .

Experimente online! ou Verifique todos os casos de teste.

Explicação

OIæ%13AS  Input: string Z
O         Ordinal. Convert each char in Z to its ASCII value
 I        Increments. Find the difference between each pair of values
  æ%13    Symmetric mod. Maps each to the interval (-13, 13]
      A   Absolute value of each
       S  Sum
          Return implicitly
milhas
fonte
6
I came across æ% while reading through the built-ins the other day, and it was pretty much made for this (type of) problem: OIæ%13AS
Martin Ender
Eu acho que isso é 9 bytes ( æsão dois).
Aleksei Zabrodskii 18/09/16
1
@elmigranto Jelly tem uma página de código que codifica cada um de seus caracteres em um byte: github.com/DennisMitchell/jelly/wiki/Code-page
ruds
10

Haskell, 57 56 bytes

q=map$(-)13.abs
sum.q.q.(zipWith(-)=<<tail).map fromEnum

Exemplo de uso: sum.q.q.(zipWith(-)=<<tail).map fromEnum $ "valleys"-> 35.

Como funciona:

q=map$(-)13.abs                -- helper function.
                               -- Non-pointfree: q l = map (\e -> 13 - abs e) l
                               -- foreach element e in list l: subtract the
                               -- absolute value of e from 13

               map fromEnum    -- convert to ascii values
      zipWith(-)=<<tail        -- build differences of neighbor elements
  q.q                          -- apply q twice on every element
sum                            -- sum it up

Edit: @Damien salvou um byte. Obrigado!

nimi
fonte
obrigado pelo truque da distância de rotação ( q.q) #
Leif Willerts 17/16
Uau, um bom! Você pode adicionar mapna definição de qum byte a menos #
Damien
@ Damien: bem localizado. Obrigado!
nimi
8

MATL , 14 , 10 bytes

dt_v26\X<s

Experimente online!

Obrigado @Suever por salvar 4 bytes!

Explicação:

d           % Take the difference between consecutive characters
 t_         % Make a copy of this array, and take the negative of each element
   v        % Join these two arrays together into a matrix with height 2
    26\     % Mod 26 of each element
       X<   % Grab the minimum of each column
         s  % Sum these. Implicitly print

Versão anterior:

d26\t13>26*-|s
DJMcMayhem
fonte
6

Python 3, 69 68 bytes

lambda s:sum([13-abs(13-abs(ord(a)-ord(b)))for a,b in zip(s,s[1:])])

Demolir:

lambda s:
         sum(                                                      )
             [                             for a,b in zip(s,s[1:])]
              13-abs(13-abs(ord(a)-ord(b)))
busukxuan
fonte
1
Você pode perder um byte, removendo o espaço antesfor
Daniel
@ Dopapp Oh sim, obrigado!
busukxuan
2
Você poderia tomar a entrada como uma lista de caracteres e uso de recursão para salvar 3 bytes:f=lambda a,b,*s:13-abs(13-abs(ord(a)-ord(b)))+(s and f(b,*s)or 0)
Jonathan Allan
5

Java, 126 120 117 bytes

int f(String s){byte[]z=s.getBytes();int r=0,i=0,e;for(;++i<z.length;r+=(e=(26+z[i]-z[i-1])%26)<14?e:26-e);return r;}

Agradecemos a @KevinCruijssen por apontar um bug na versão original e sugerir que o loop for fique vazio.

O uso de (26 + z[i] - z[i - 1]) % 26)é inspirado em um comentário de @Neil em outra resposta. (26 + ...)%26serve ao mesmo propósito que Math.abs(...)por causa de ...? e : 26 - e.

Ungolfed :

int f(String s) {
    byte[]z = s.getBytes();
    int r = 0, i = 0, e;
    for (; ++i < z.length; r += (e = (26 + z[i] - z[i - 1]) % 26) < 14 ? e : 26 - e);
    return r;
}
todeale
fonte
Bem vindo ao site! Que língua é essa? Quantos caracteres / bytes são? Você deve [edit] those details into the top of your post, with this markdown: #Language, n bytes` #
DJMcMayhem
Está bem. Obrigado. Eu editei. Alguma melhoria? :)
todeale 17/09/16
1
Você está perdendo um -antes de um ena sua versão não-destruída.
Neil
2
Bem-vindo ao PPCG! Hmm, estou recebendo um erro "Incompatibilidade de tipo: não é possível converter de int para byte" em e=z[i]-z[i-1];Então, você precisa de uma conversão para (byte)ou para alterar epara int. Além disso, você pode remover os suportes para-circuito, colocando tudo dentro do loop for, como este: int f(String s){byte[]z=s.getBytes();int r=0,i=0,e;for(;++i<z.length;r+=(e=z[i]-z[i-1])>0?e<14?e:26-e:-e<14?-e:e+26);return r;}(PS: O inverteu o ciclo for é, infelizmente, o mesmo comprimento: int f(String s){byte[]z=s.getBytes();int r=0,i=z.length-1,e;for(;i>0;r+=(e=z[i]-z[--i])>0?e<14?e:26-e:-e<14?-e:e+26);return r;}.
Kevin Cruijssen
1
Muito obrigado @KevinCruijssen: D. Sua sugestão ajudou muito.
todeale 20/09/16
3

JavaScript (ES6), 84 82 79 bytes

Economizou 3 bytes graças a Cyoce:

f=([d,...s],p=parseInt,v=(26+p(s[0],36)-p(d,36))%26)=>s[0]?f(s)+(v>13?26-v:v):0

Explicação:

f=(
  [d,...s],                    //Destructured input, separates first char from the rest
  p=parseInt,                  //p used as parseInt
  v=(26+p(s[0],36)-p(d,36))%26 //v is the absolute value of the difference using base 36 to get number from char
  )
)=>
  s[0]?                        //If there is at least two char in the input
    f(s)                       //sum recursive call
    +                          //added to
    (v>13?26-v:v)              //the current shortest path
  :                            //else
    0                          //ends the recursion, returns 0

Exemplo:
Chamada: f('golf')
Saída:17


Soluções anteriores:

82 bytes graças a Neil:

f=([d,...s],v=(26+parseInt(s[0],36)-parseInt(d,36))%26)=>s[0]?f(s)+(v>13?26-v:v):0

84 bytes:

f=([d,...s],v=Math.abs(parseInt(s[0],36)-parseInt(d,36)))=>s[0]?f(s)+(v>13?26-v:v):0
Hedi
fonte
1
Em vez de Math.abs(...)você pode usar (26+...)%26; isso funciona porque você está invertendo valores acima de 13 de qualquer maneira. (Acho que é assim que a resposta MATL funciona.)
Neil
1
Salve alguns bytes acrescentando o código com p=parseInt;e, em seguida, usando em p()vez deparseInt()
Cyoce 20/16/16
3

Ruby, 73 bytes

->x{eval x.chars.each_cons(2).map{|a,b|13-(13-(a.ord-b.ord).abs).abs}*?+}
cia_rana
fonte
2

PHP, 93 bytes

for(;++$i<strlen($s=$argv[1]);)$r+=13<($a=abs(ord($s[$i-1])-ord($s[$i])))?$a=26-$a:$a;echo$r;
Jörg Hülsermann
fonte
2

05AB1E , 12 bytes

SÇ¥YFÄ5Ø-}(O

Explicação

SÇ                   # convert to list of ascii values
  ¥                  # take delta's
   YF    }           # 2 times do
     Ä5Ø-            # for x in list: abs(x) - 13
          (O         # negate and sum

Experimente online!

Emigna
fonte
São 12 símbolos, não bytes. O comprimento de bytes seria 16 para UTF-8.
Aleksei Zabrodskii 18/09/16
@elmigranto: De fato. Em UTF-8, esse seria o caso, mas 05AB1E usa CP-1252, em que são 12 bytes.
Emigna
2

Perl, 46 bytes

Inclui +3 para -p(o código contém ')

Dê entrada no STDIN sem nova linha final:

echo -n zaza | stringd.pl

stringd.pl:

#!/usr/bin/perl -p
s%.%$\+=13-abs 13-abs ord($&)-ord$'.$&%eg}{
Ton Hospel
fonte
2

Raquete 119 bytes

(λ(s)(for/sum((i(sub1(string-length s))))(abs(-(char->integer
(string-ref s i))(char->integer(string-ref s(+ 1 i)))))))

Teste:

(f "golf")

Saída:

17

Versão detalhada:

(define(f s)
  (for/sum((i(sub1(string-length s))))
    (abs(-(char->integer(string-ref s i))
          (char->integer(string-ref s(+ 1 i)))))))
rnso
fonte
Você pode substituir (define(f s)por (lambda(s)2 bytes mais curtos (funções anônimas são boas).
fede s.
1
Espere, o Racket também deve demorar (λ(s), o que, se em utf8 for de 6 bytes, penso
fede s.
Fiz isso. Obrigado.
Rnso 17/09/16
2

C #, 87 85 bytes

Solução aprimorada - substituiu Math.Abs ​​() pelo truque add & modulo para economizar 2 bytes:

s=>{int l=0,d,i=0;for(;i<s.Length-1;)l+=(d=(s[i]-s[++i]+26)%26)>13?26-d:d;return l;};

Solução inicial :

s=>{int l=0,d,i=0;for(;i<s.Length-1;)l+=(d=Math.Abs(s[i]-s[++i]))>13?26-d:d;return l;};

Experimente online!

Fonte completa, incluindo casos de teste:

using System;

namespace StringDistance
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<string,int>f= s=>{int l=0,d,i=0;for(;i<s.Length-1;)l+=(d=Math.Abs(s[i]-s[++i]))>13?26-d:d;return l;};

            Console.WriteLine(f("golf"));   //17
            Console.WriteLine(f("aa"));     //0
            Console.WriteLine(f("stack"));  //18
            Console.WriteLine(f("zaza"));   //3
            Console.WriteLine(f("valleys"));//35
        }
    }
}
adrianmp
fonte
2

Na verdade, 21 bytes

Baseado parcialmente na resposta Ruby de cia_rana .

Houve um erro com O(nesse caso, map ord () sobre uma string) em que ele não funcionaria com d(desenfileirar o elemento bottom) e p(pop primeiro elemento) sem primeiro converter o mapa em uma lista com #. Este bug foi corrigido, mas como essa correção é mais recente que esse desafio, eu continuei #.

Edit: E a contagem de bytes está errada desde setembro. Ops.

Sugestões de golfe são bem-vindas. Experimente online!

O#;dX@pX♀-`A;úl-km`MΣ

Ungolfing

         Implicit input string.
          The string should already be enclosed in quotation marks.
O#       Map ord() over the string and convert the map to a list. Call it ords.
;        Duplicate ords.
dX       Dequeue the last element and discard it.
@        Swap the with the duplicate ords.
pX       Pop the last element and discard it. Stack: ords[:-1], ords[1:]
♀-       Subtract each element of the second list from each element of the first list.
          This subtraction is equivalent to getting the first differences of ords.
`...`M   Map the following function over the first differences. Variable i.
  A;       abs(i) and duplicate.
  úl       Push the lowercase alphabet and get its length. A golfy way to push 26.
  -        26-i
  k        Pop all elements from stack and convert to list. Stack: [i, 26-i]
  m        min([i, 26-i])
Σ        Sum the result of the map.
         Implicit return.
Sherlock9
fonte
1

Java 7.128 bytes

 int f(String s){char[]c=s.toCharArray();int t=0;for(int i=1,a;i<c.length;a=Math.abs(c[i]-c[i++-1]),t+=26-a<a?26-a:a);return t;}

Ungolfed

 int f(String s){
 char[]c=s.toCharArray();
 int t=0;
 for(int i=1,a;
     i<c.length;
   a=Math.abs(c[i]-c[i++-1]),t+=26-a<a?26-a:a);
return t;
 }
Numberknot
fonte
1

Pitão, 20 bytes

Lm-13.adbsyy-M.:CMQ2

Um programa que recebe a entrada de uma string entre aspas no STDIN e imprime o resultado.

Experimente online

Como funciona

Lm-13.adbsyy-M.:CMQ2  Program. Input: Q
L                     def y(b) ->
 m      b              Map over b with variable d:
  -13                   13-
     .ad                abs(d)
                CMQ   Map code-point over Q
              .:   2  All length 2 sublists of that
            -M        Map subtraction over that
          yy          y(y(that))
         s            Sum of that
                      Implicitly print
TheBikingViking
fonte
1

dc + od, 65 bytes

od -tuC|dc -e'?dsN0sT[lNrdsNr-d*vdD[26-]sS<Sd*vlT+sTd0<R]dsRxlTp'

Explicação:

Como no dc você não pode acessar os caracteres de uma string, usei od para obter os valores ASCII. Estes serão processados ​​na ordem inversa a partir da pilha (contêiner LIFO) da seguinte forma:

dsN0sT             # initialize N (neighbor) = top ASCII value, and T (total) = 0
[lNrdsNr-          # loop 'R': calculate difference between current value and N,
                   #updating N (on the first iteration the difference is 0)
   d*vdD[26-]sS<S  # get absolute value (d*v), push 13 (D) and call 'S' to subtract
                   #26 if the difference is greater than 13
   d*vlT+sT        # get absolute value again and add it to T
d0<R]dsR           # repeat loop for the rest of the ASCII values
xlTp               # the main: call 'R' and print T at the end

Corre:

echo -n "golf" | ./string_distance.sh

Saída:

17
seshoumara
fonte
1

C, 82 86 83 76 bytes

t,u;f(char*s){for(t=0;*++s;u=*s-s[-1],t+=(u=u<0?-u:u)>13?26-u:u);return t;}

Supõe que a sequência de entrada tenha pelo menos um caractere. Isso não requer#include<stdlib.h>

Edit: Argh, pontos de sequência!

Experimente no Ideone

teto
fonte
em ideone compilador a string "nwlrbb" e todos corda do rand eu tento 6 len devolver todos os 0 mas não parece 0 o resultado ....
RosLuP
Sim, agora parece ok ...
RosLuP 23/09
1

C, 70 bytes 76 bytes

k,i;f(char *s){for(i=0;*++s;i+=(k=abs(*s-s[-1]))>13?26-k:k);return i;}
NoSeatbelts
fonte
1

Scala, 68 bytes

def f(s:String)=(for(i<-0 to s.length-2)yield (s(i)-s(i+1)).abs).sum

Críticas são bem-vindas.

Ele mesmo12794
fonte
1

C #, 217 bytes

Golfe:

IEnumerable<int>g(string k){Func<Char,int>x=(c)=>int.Parse(""+Convert.ToByte(c))-97;for(int i=0;i<k.Length-1;i++){var f=x(k[i]);var s=x(k[i+1]);var d=Math.Abs(f-s);yield return d>13?26-Math.Max(f,s)+Math.Min(f,s):d;}}

Ungolfed:

IEnumerable<int> g(string k)
{
  Func<Char, int> x = (c) => int.Parse("" + Convert.ToByte(c)) - 97;
  for (int i = 0; i < k.Length - 1; i++)
  {
    var f = x(k[i]);
    var s = x(k[i + 1]);
    var d = Math.Abs(f - s);
    yield return d > 13 ? 26 - Math.Max(f, s) + Math.Min(f, s) : d;
  }
}

Saída:

aa: 0
stack: 18
zaza: 3
valleys: 35

'a' é 97 quando convertido em bytes; portanto, 97 é subtraído de cada um. Se a diferença for maior que 13 (ou seja, metade do alfabeto), subtraia as diferenças entre cada caractere (valor de bytes) de 26. Uma adição de última hora de "yield return" me salvou alguns bytes!

Pete Arden
fonte
1
Dois espaços em branco inúteis: ambos antes dos 's'.
Yytsi 27/10/16
0

Python 3, 126 bytes

Com lista na compreensão.

d=input()
print(sum([min(abs(x-y),x+26-y)for x,y in[map(lambda x:(ord(x)-97),sorted(d[i:i+2]))for i in range(len(d))][:-1]]))
edelbitter
fonte
Boa resposta. Você pode substituir abs(x-y)por y-xdesde a chamada a sortedfazer x < y.
todeale 24/09/16
0

PHP, 79 bytes

for($w=$argv[1];$w[++$i];)$s+=13-abs(13-abs(ord($w[$i-1])-ord($w[$i])));echo$s;
Titus
fonte
0

Java, 109 bytes

int f(String s){int x=0,t,a=0;for(byte b:s.getBytes()){t=a>0?(a-b+26)%26:0;t=t>13?26-t:t;x+=t;a=b;}return x;
Ekeko
fonte