Challenge
Given an input of an all-lowercase string [a-z]
, output the total distance between the letters.
Example
Input: golf
Distance from g to o : 8
Distance from o to l : 3
Distance from l to f : 6
Output: 17
Rules
- Standard loopholes forbidden
- This is code-golf - shortest answer in bytes wins.
- The alphabet can be traversed from either direction. You must always use the shortest path. (i.e the distance between
x
andc
is 5).
1
Test cases
Input: aa
Output: 0
Input: stack
Output: 18
Input: zaza
Output: 3
Input: valleys
Output: 35
23 Answers 23
Jelly, (削除) 11 (削除ここまで) 8 bytes
OIæ%13AS
Saved 3 bytes thanks to @Martin Ender.
Try it online! or Verify all test cases.
Explanation
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
-
6\$\begingroup\$ 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
\$\endgroup\$Martin Ender– Martin Ender2016年09月17日 15:44:53 +00:00Commented Sep 17, 2016 at 15:44 -
\$\begingroup\$ I think this is 9 bytes (
æ
is two). \$\endgroup\$Aleksei Zabrodskii– Aleksei Zabrodskii2016年09月18日 09:48:22 +00:00Commented Sep 18, 2016 at 9:48 -
1\$\begingroup\$ @elmigranto Jelly has a codepage that encodes each of its characters in one byte: github.com/DennisMitchell/jelly/wiki/Code-page \$\endgroup\$ruds– ruds2016年09月18日 15:54:37 +00:00Commented Sep 18, 2016 at 15:54
Haskell, (削除) 57 (削除ここまで) 56 bytes
q=map$(-)13.abs
sum.q.q.(zipWith(-)=<<tail).map fromEnum
Usage example: sum.q.q.(zipWith(-)=<<tail).map fromEnum $ "valleys"
-> 35
.
How it works:
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 saved one byte. Thanks!
-
\$\begingroup\$ Wow nice one! You can add
map
in the definition ofq
for one byte less \$\endgroup\$Damien– Damien2016年09月21日 11:21:23 +00:00Commented Sep 21, 2016 at 11:21 -
\$\begingroup\$ @Damien: well spotted. Thanks! \$\endgroup\$nimi– nimi2016年09月21日 15:42:32 +00:00Commented Sep 21, 2016 at 15:42
MATL, (削除) 14 (削除ここまで), 10 bytes
dt_v26\X<s
Thanks @Suever for saving 4 bytes!
Explanation:
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
Previous version:
d26\t13>26*-|s
Python 3, (削除) 69 (削除ここまで) 68 bytes
lambda s:sum([13-abs(13-abs(ord(a)-ord(b)))for a,b in zip(s,s[1:])])
Breakdown:
lambda s:
sum( )
[ for a,b in zip(s,s[1:])]
13-abs(13-abs(ord(a)-ord(b)))
-
1\$\begingroup\$ You can lose one byte by removing the space before
for
\$\endgroup\$Daniel– Daniel2016年09月17日 15:25:33 +00:00Commented Sep 17, 2016 at 15:25 -
2\$\begingroup\$ You could take the input as a list of characters and use recursion to save 3 bytes:
f=lambda a,b,*s:13-abs(13-abs(ord(a)-ord(b)))+(s and f(b,*s)or 0)
\$\endgroup\$Jonathan Allan– Jonathan Allan2016年09月17日 20:46:52 +00:00Commented Sep 17, 2016 at 20:46
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;}
Thanks to @KevinCruijssen for pointing out a bug in the original version and suggesting to make the for-loop empty.
The use of (26 + z[i] - z[i - 1]) % 26)
is inspired from a comment by @Neil on another answer. (26 + ...)%26
serves the same purpose as Math.abs(...)
because of ...? 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;
}
-
\$\begingroup\$ Welcome to the site! What language is this? How many characters/bytes is it? You should
[edit] those details into the top of your post, with this markdown:
#Language, n bytes` \$\endgroup\$DJMcMayhem– DJMcMayhem2016年09月17日 19:12:11 +00:00Commented Sep 17, 2016 at 19:12 -
\$\begingroup\$ Ok. Thanks. I've edited it. Any improvement? :) \$\endgroup\$todeale– todeale2016年09月17日 19:16:14 +00:00Commented Sep 17, 2016 at 19:16
-
1\$\begingroup\$ You're missing a
-
before ane
in your ungolfed version. \$\endgroup\$Neil– Neil2016年09月19日 09:02:07 +00:00Commented Sep 19, 2016 at 9:02 -
2\$\begingroup\$ Welcome to PPCG! Hmm, I'm getting a "Type mismatch: cannot convert from int to byte" error at
e=z[i]-z[i-1];
So you either need a cast to(byte)
or change thee
toint
. Also, you can remove the for-loop brackets by placing everything inside the for-loop, like this: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: The reversed the for-loop is unfortunately the same length: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;}
. \$\endgroup\$Kevin Cruijssen– Kevin Cruijssen2016年09月20日 13:55:55 +00:00Commented Sep 20, 2016 at 13:55 -
1\$\begingroup\$ Thanks a lot @KevinCruijssen :D. Your suggestion has helped a lot. \$\endgroup\$todeale– todeale2016年09月20日 15:00:01 +00:00Commented Sep 20, 2016 at 15:00
JavaScript (ES6), (削除) 84 (削除ここまで) (削除) 82 (削除ここまで) 79 bytes
Saved 3 bytes thanks to 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
Explanation:
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
Example:
Call: f('golf')
Output: 17
Previous solutions :
82 bytes thanks to 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
-
1\$\begingroup\$ Instead of
Math.abs(...)
you can use(26+...)%26
; this works because you're flipping values above 13 anyway. (I think this is how the MATL answer works.) \$\endgroup\$Neil– Neil2016年09月17日 10:44:32 +00:00Commented Sep 17, 2016 at 10:44 -
1\$\begingroup\$ Save some bytes by prepending the code with
p=parseInt;
and then usingp()
instead ofparseInt()
\$\endgroup\$Cyoce– Cyoce2016年09月20日 15:21:28 +00:00Commented Sep 20, 2016 at 15:21
Ruby, 73 bytes
->x{eval x.chars.each_cons(2).map{|a,b|13-(13-(a.ord-b.ord).abs).abs}*?+}
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;
05AB1E, 12 bytes
SÇ\YFÄ5Ø-}(O
Explanation
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
-
\$\begingroup\$ It's 12 symbols, not bytes. Byte-length would be 16 for UTF-8. \$\endgroup\$Aleksei Zabrodskii– Aleksei Zabrodskii2016年09月18日 09:49:26 +00:00Commented Sep 18, 2016 at 9:49
-
\$\begingroup\$ @elmigranto: Indeed. In UTF-8 that would be the case, but 05AB1E uses CP-1252 where this is 12 bytes. \$\endgroup\$Emigna– Emigna2016年09月18日 10:06:33 +00:00Commented Sep 18, 2016 at 10:06
Perl, 46 bytes
Includes +3 for -p
(code contains '
)
Give input on STDIN without final newline:
echo -n zaza | stringd.pl
stringd.pl
:
#!/usr/bin/perl -p
s%.%$\+=13-abs 13-abs ord($&)-ord$'.$&%eg}{
Racket 119 bytes
(λ(s)(for/sum((i(sub1(string-length s))))(abs(-(char->integer
(string-ref s i))(char->integer(string-ref s(+ 1 i)))))))
Testing:
(f "golf")
Output:
17
Detailed version:
(define(f s)
(for/sum((i(sub1(string-length s))))
(abs(-(char->integer(string-ref s i))
(char->integer(string-ref s(+ 1 i)))))))
-
\$\begingroup\$ You could replace
(define(f s)
with(lambda(s)
, 2 bytes shorter (anonymous functions are fine). \$\endgroup\$fede s.– fede s.2016年09月17日 21:15:43 +00:00Commented Sep 17, 2016 at 21:15 -
1\$\begingroup\$ Wait, Racket should take
(λ(s)
too, which if in utf8 is 6 bytes i think \$\endgroup\$fede s.– fede s.2016年09月17日 21:17:45 +00:00Commented Sep 17, 2016 at 21:17
C#, (削除) 87 (削除ここまで) 85 bytes
Improved solution - replaced Math.Abs() with the add & modulo trick to save 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;};
Initial solution:
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;};
Full source, including test cases:
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
}
}
}
Actually, 21 bytes
Based partially on cia_rana's Ruby answer.
There was a bug with O
(in this case, map ord() over a string) where it would not work with d
(dequeue bottom element) and p
(pop first element) without first converting the map to a list with #
. This bug has been fixed, but as that fix is newer than this challenge, so I've kept #
in.
Edit: And the byte count has been wrong since September. Whoops.
Golfing suggestions welcome. Try it 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.
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;
}
Pyth, 20 bytes
Lm-13.adbsyy-M.:CMQ2
A program that takes input of a quoted string on STDIN and prints the result.
How it works
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
dc + od, 65 bytes
od -tuC|dc -e'?dsN0sT[lNrdsNr-d*vdD[26-]sS<Sd*vlT+sTd0<R]dsRxlTp'
Explanation:
Because in dc you can't access a string's characters, I used od to get the ASCII values. These will be processed in reverse order from the stack (LIFO container) like so:
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
Run:
echo -n "golf" | ./string_distance.sh
Output:
17
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;}
Assumes input string is at least one character long. This doesn't require #include<stdlib.h>
Edit: Argh, sequence points!
-
\$\begingroup\$ in ideone compiler the string "nwlrbb" and all the rand string i try 6 len return all 0 but it seems not 0 the result.... \$\endgroup\$user58988– user589882016年09月23日 08:56:55 +00:00Commented Sep 23, 2016 at 8:56
-
\$\begingroup\$ yes now it seems ok... \$\endgroup\$user58988– user589882016年09月23日 23:02:19 +00:00Commented Sep 23, 2016 at 23:02
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;}
Scala, 68 bytes
def f(s:String)=(for(i<-0 to s.length-2)yield (s(i)-s(i+1)).abs).sum
Criticism is welcome.
C#, 217 bytes
Golfed:
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;
}
}
Output:
aa: 0
stack: 18
zaza: 3
valleys: 35
'a' is 97 when converted to bytes, so 97 is subtracted from each one. If the difference is greater than 13 (ie, half of the alphabet), then subtract the differences between each character (byte value) from 26. A last minute addition of "yield return" saved me a few bytes!
-
1\$\begingroup\$ Two useless whitespaces: both before 's'. \$\endgroup\$Yytsi– Yytsi2016年10月27日 17:03:50 +00:00Commented Oct 27, 2016 at 17:03
Python 3, 126 bytes
With list incomprehension.
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]]))
-
\$\begingroup\$ Nice answer. You could replace
abs(x-y)
byy-x
since the call tosorted
makex < y
. \$\endgroup\$todeale– todeale2016年09月24日 07:58:51 +00:00Commented Sep 24, 2016 at 7:58
PHP, 79 bytes
for($w=$argv[1];$w[++$i];)$s+=13-abs(13-abs(ord($w[$i-1])-ord($w[$i])));echo$s;
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;