22
\$\begingroup\$

Write a program that accepts a single lowercase word as input and outputs the number of pairs of letters that have the same number of letters between them in the word as in the alphabet.

For example, in the word 'nature', we have 4 pairs:

  • nr: since there are three letters between them inside the word (a, t, u) and three letters between them in the alphabet (o, p, q)
  • ae: since there are three letters between them inside the word (t, u, r) and three letters between them in the alphabet (b, c, d)
  • tu: since there are no letters between them inside the word and no letters between them in the alphabet
  • tr: since there is one letter between them inside the word (u) and one letter between them in the alphabet (s)

Since there are four pairs, the output in this case should be 4.

\$\endgroup\$
7
  • 11
    \$\begingroup\$ The wording can be clarified a bit more. \$\endgroup\$
    – Optimizer
    Nov 8, 2015 at 12:15
  • \$\begingroup\$ I don't get the question. How are the letters a,t,u going to be inside nr? And all the following examples... (cc @flodel) \$\endgroup\$
    – nicael
    Nov 8, 2015 at 15:25
  • \$\begingroup\$ If you spell out n.a.t.u.r.e, the n and r are at the 1st and 5th position. So there are three letters between them. They are a, t, and u, at the 2nd, 3rd and 4th position. That's what the text means by there are three letters between n and r inside the word. \$\endgroup\$
    – flodel
    Nov 8, 2015 at 16:36
  • \$\begingroup\$ @flodel You're right in the edit; I missed the 4th pair. \$\endgroup\$ Nov 10, 2015 at 8:42
  • 1
    \$\begingroup\$ What if the word were rjjjnfffr? Would that be one pair (nr) or two pairs (nr and rn)? And what about abzab? Is that two pairs of ab or one? \$\endgroup\$ Nov 17, 2015 at 19:22

16 Answers 16

5
\$\begingroup\$

Pyth, 19 bytes

lfqF-MSMCT.cCUBCMz2

Try it online: Demonstration

Explanation:

lfqF-MSMCT.cCUBCMz2
                 z   read a string from input
               CM    convert into list of ascii-values
            CUB      create a list of pairs (ascii-value, index in string)
          .c      2  all combinations of length 2
 f                   filter for combinations T, which satisfy:
        CT              transpose T ((ascii1, ascii2), (index1, index2)
      SM                sort each list
    -M                  create the the difference for each
  qF                    check if they are equal
l                    print the number of remaining combinations
\$\endgroup\$
4
\$\begingroup\$

R, 110 bytes

function(s){w=strsplit(s,"")[[1]]
O=outer
n=nchar(s)
sum(abs(O(r<-match(w,letters),r,"-"))==O(1:n,1:n,"-"))-n}

Degolfed:

F = function(s){
   chars = strsplit(s,"")[[1]]
   num_chars = nchar(s)
   letter_rank = match(chars, letters)
   rank_dist = abs(outer(letter_rank, letter_rank, "-"))
   position_dist = outer(1:num_chars, 1:num_chars, "-")
   return(sum(rank_dist == position_dist) - num_chars)
}

F("nature")
# [1] 4
F("supercalifragilisticexpialidocious")
# [1] 25
\$\endgroup\$
3
\$\begingroup\$

Octave, 41 bytes

@(s)nnz(abs(s-s')==(t=1:(u=nnz(s)))-t')-u
\$\endgroup\$
3
\$\begingroup\$

CJam, 36 bytes

r:A,{)Aew}%1>{{:B,B0=BW=-z)=}%}%e_:+

Try it Online.

\$\endgroup\$
3
+50
\$\begingroup\$

Husk, 8 bytes

#S≡Γ·…→Q

Try it online!

Explanation

#S≡Γ·…→Q
       Q all continuous sublists
#        number of sublists which satisfy:
 S≡      has the same shape and distribution of truthy/falsy values as: 
   Γ·…→  the range between its first and last character?
\$\endgroup\$
2
  • \$\begingroup\$ Awarded bounty for picking the right tool for the job haha. \$\endgroup\$ Apr 18, 2021 at 5:35
  • \$\begingroup\$ wow, didn't expect that. Thanks for the bounty! \$\endgroup\$
    – Razetime
    Apr 18, 2021 at 5:37
2
\$\begingroup\$

J, 27 bytes

#-:@-~#\+/@,@:=&(|@-/~)3&u:

Usage:

   (#-:@-~#\+/@,@:=&(|@-/~)3&u:) 'nature'
4

Explanation:

#-:@-~#\+/@,@:=&(|@-/~)3&u:
      #\                    lengths of input prefixes (1,2,...,length)
                       3&u: codepoints of input
               &(     )     with the last two do parallel:
                 |@-/~      create difference table with itself and take absolute values
              =             compare the elements of the two difference tables
        +/@,@:              sum the table              
#   -~                      subtract the length of the input (self-similar letters)
 -:@                        half the result (each pair was accounted twice)

Try it online here.

\$\endgroup\$
2
\$\begingroup\$

CJam, 25 bytes

l:T,_2m*{_:-\Tf=:-z=},,\-

Try it online

Explanation:

l     Get input.
:T    Store in variable T for later use.
,     Calculate length.
_     Copy for use at the very end.
2m*   Use Cartesian power to calculate all possible position pairs.
{     Start filter.
  _     Create copy of index pair.
  :-    Calculate difference between indices.
  \     Swap copy of index pair to top.
  T     Get input string stored in variable T.
  f=    Extract the letters for the index pair.
  :-    Calculate difference of the two letters.
  z     Take the absolute value.
  =     Compare index difference and letter difference.
},    End filter.
,\
-     Pairs of identical indices passed the filter. Eliminate them from the
      count by subtracting the length of the input.
\$\endgroup\$
2
\$\begingroup\$

JavaScript (ES6), 98 bytes

f=w=>(p=0,q="charCodeAt",[...w].map((c,a)=>{for(b=a;w[++b];)p+=Math.abs(w[q](a)-w[q](b))==b-a}),p)

Usage

f("nature")
=> 4

Explanation

f=w=>(
  p=0,                                 // p = number of pairs
  q="charCodeAt",
  [...w].map((c,a)=>{                  // iterate through each character of input
                                       // a = character A index
    for(b=a;w[++b];)                   // iterate through the remaining input characters
                                       // b = character B index
      p+=                              // add 1 to p if true or 0 if false
        Math.abs(w[q](a)-w[q](b))==b-a // compare absolute difference of character codes
                                       //     to difference of indices
  }),
  p                                    // return p
)
\$\endgroup\$
2
\$\begingroup\$

Jelly, 32 16 bytes

ḢØaṣU1¦=
ṫJÇ€Fċ1

Try it online!

–16 when I learned how to reverse just the first element of a list.

How?

ḢØaṣU1¦=  - helper monadic link, e.g. nature
Ḣ         - pop first character       n
 Øa       - lowercase alphabet        abcdefghijklmnopqrstuvwxyz
   ṣ      - split list                abcdefghijklm opqrstuvwxyz
    U1¦   - reverse first element     mlkjihgfedcba opqrstuvwxyz
       =  - equate with string        mlkjihgfedcba opqrstuvwxyz
                                    = ature         ature
                                   -> 00000hgfedcba 00010tuvwxyz

ṫJÇ€Fċ1   - main monadic link, e.g. nature
 J        - range                   1 2 3 4 5 6
ṫ         - tail; remove n-1 chars  nature ature ture ure re e
  ǀ      - map previous link       00000hgfedcba 00010tuvwxyz ...
    F     - flatten                 00000hgfedcba 00010tuvwxyz ...
     ċ1   - count 1s                4
\$\endgroup\$
1
\$\begingroup\$

Python 2, 91 chars

lambda i:sum(y-x==abs(ord(i[y])-ord(i[x]))for x in range(len(i))for y in range(x+1,len(i)))
\$\endgroup\$
1
\$\begingroup\$

MATLAB, 84 bytes

s=input('');disp(sum(diff(nchoosek(find(s),2),[],2)==abs(diff(nchoosek(s,2),[],2))))

This line asks for a string as input. It then creates all possible pairs of letters and does the same for their corresponding indices. Then we determine whether the (absolute) difference of the values matches to finally sum all cases where it does. The result is displayed in the command window.

\$\endgroup\$
1
\$\begingroup\$

JavaScript ES7, 93

Using array comprehension. ES6 with .map.map.map is 2 bytes longer.

Test running the snippet below with Firefox

f=s=>[for(x of s)x.charCodeAt()].map((a,i,s)=>s.map((b,j)=>t+=j>i&(b>a?b-a:a-b)==j-i),t=0)&&t

document.write('nature'+'\n'+f('nature'))

\$\endgroup\$
1
\$\begingroup\$

PowerShell, 114 100 Bytes

param($a)$b=$a.length;0..($b-1)|%{$i=$_;($_+1)..$b|%{$o+=[math]::Abs(+$a[$_]-$a[$i])-eq($_-$i)}};+$o

Pretty straight-forward, but uses a couple tricks.

  • param(..) takes our input, saves it to $a.
  • We set a temp variable $b to be the .length of our input. This saves a byte later.
  • 0..($b-1)|%{..} is the equivalent of a for($i=0;$i-le($b-1);$i++){..} loop, but quite a lot shorter.
  • However, we need to set variable $i in order to keep that going into ...
  • ($_+1)..$b|%{..} the next for loop, since $_ is only positional to the inner loop.
  • We then use a lengthy .NET call to check if the absolute value between our two characters (here we use implicit casting with prepending + to save a bunch of bytes) is -equal to the positional difference in the array. Since we're explicitly given lowercase input, we don't need to do case conversion. This statement will return either True or False.
  • We blatantly abuse implicit casting again to accumulate that result into $o, so True will add 1, while False will add 0.
  • Once the loops are finished, we output $o. Note we need to do the same tricksy-cast-to-int with + to avoid printing False if there were no matches.
\$\endgroup\$
0
\$\begingroup\$

Ruby, 74

 ->s{[*0...s.size].permutation(2).count{|i,j|(s[i].ord-s[j].ord).abs==j-i}}

Nothing super interesting here. I would have loved to use eval("s[i].#{["succ"]*(j-i)*?.}") but... seemed too long.

\$\endgroup\$
0
\$\begingroup\$

Matlab(94)(80)

Edit: I didnt take in case inversed alphabetic order,as (t,r) in 'nature', so more bytes to upweight :(

@(a)sum(arrayfun(@(x)sum(1:nnz(find(a==fix(x/2)+(-1)^x*(1:1:nnz(a))))-1),2:244))

  • binomial function throws a stupid exception when k is bigger than n and I cant catch exceptions inside arraycell function, otherwise I could golf it more. Who needs a built in function ??

    Now I could just do it by hand, simplifying binomial(n,2)=n/(2(n-2)!)=n(n-1)/2. remark that this last value reprensents sum of integers from 1 to n-1, this doesnt throw any exception in matlab, God bless maths.

  • Ps: this method is diferent than slvrbld's

Execution

  >> ans('abef')

  ans =

       2

  >> ans('abcd')

  ans =

       6

  >> ans('nature')

  ans =

       4
\$\endgroup\$
2
  • \$\begingroup\$ I think it's safe to remove ,'s' from input()'s arguments. Saves you 4 bytes. Furthermore, it seems to fail on longer strings (e.g. 'supercalifragilisticexpialidocious' that flodel used as test case) due to the hardcoded for-loop range... you may want to fix that. \$\endgroup\$
    – slvrbld
    Nov 12, 2015 at 8:14
  • \$\begingroup\$ @slvrbld i doont think i need that,see the newest edit \$\endgroup\$
    – Abr001am
    Nov 17, 2015 at 22:06
0
\$\begingroup\$

Jelly, 12 bytes

ONƬ_JLƙ€c2SS

Try it online!

Got too caught up in figuring out the best way to do this with and forgot to post an answer at all, but now that I've remembered I think I might leave that as an exercise to @cjquines ;)

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.