21
\$\begingroup\$

Title misspelled on purpose. Read more to find out why.

Your task: given a delimited string or list including the characters A,B,C,D, output the indexes of all the adjacent equal characters. Output can be multiple strings/integers on multiple lines, a list/array, or a delimited string.

All output should be in a list or string, or multiple printed lines. Each printed line, if there are multiple, should only contain 1 string or number. Trailing whatevers are okay.

Standard methods of input/output. Standard loopholes apply.

For example, the input 'ABCDDCBA' should output 3,4 or 4,5, depending on whether it is 0- to 1- indexed, because those numbers are the indexes of D and the D next to it.

Test cases:

Test cases have input given as a single string, and output as a ,-delimited string. Outputs are 0-indexed, add 1 to every outputted item to get it to be 1-indexed.

Input: 'ABCDCABCD'
Output: ''

Input: 'AABBCCDD'
Output: '0,1,2,3,4,5,6,7'

Input: 'ABCDDDCBA'
Output: '3,4,5'

Input: 'ABBCDD'
Output: '1,2,4,5'

This is , so shortest code wins!

\$\endgroup\$
  • \$\begingroup\$ Can we have a trailing delimiter in the output? \$\endgroup\$ – Business Cat Apr 11 '17 at 15:37
  • \$\begingroup\$ @BasicSunset Sure \$\endgroup\$ – Comrade SparklePony Apr 11 '17 at 15:38
  • 1
    \$\begingroup\$ @JonathanAllan That is okay because it outputs only one list. \$\endgroup\$ – Comrade SparklePony Apr 11 '17 at 17:25
  • 2
    \$\begingroup\$ Can indices of consecutive characters appear multiple times? E.g. for the third test case, is 3,4,4,5 valid as well? \$\endgroup\$ – Luke Apr 11 '17 at 18:18
  • 1
    \$\begingroup\$ Can you add a test case that doesn't have symmetrical matches? E.g. AABBCD -> 1,2,3,4 \$\endgroup\$ – Riley Apr 11 '17 at 18:25

24 Answers 24

5
\$\begingroup\$

MATL, 8 7 bytes

d~ftQvu

Output is 1-based.

Try it online!

Explanation with example

Consider input 'ABCDDDCBA'.

d     % Implicitly input a string. Consecutive differences
      % STACK: [1  1  1  0  0 -1 -1 -1]
~     % Negate. Each character that equals the next gives true
      % STACK: [0 0 0 1 1 0 0 0]
f     % Find: (1-based) indices of true elements
      % STACK: [4 5]
tQ    % Duplicate, add 1 element-wise
      % STACK: [4 5], [5 6]
v     % Concatenate vertically
      % STACK: [4 5; 5 6]
u     % Unique (remove duplicates). This doesn't automatically sort, but the 
      % output will be sorted because the input, read in column-major order, is 
      % Implicitly display
      % STACK: [4; 5; 6]
\$\endgroup\$
8
\$\begingroup\$

Retina, 33 29 23 bytes

Saved 6 bytes thanks to Martin Ender

T`L`:`(.)\1+
:
$.`¶
T`L

Outputs a linefeed-separated list of indices.

Try it online!

Explanation

T`L`:`(.)\1+

Transliterate runs of the same character into colons, to mark positions where there are duplicate characters.

:
$.`¶

Then replace each colon with the length of the text before it, followed by a linefeed.

T`L

Finally, delete any remaining letters.

\$\endgroup\$
7
\$\begingroup\$

Jelly, 7 bytes

JṁŒgḊÐf

1-based; returns a list of lists of the runs of indexes as allowed by the OP.

Try it online!

How?

JṁŒgḊÐf - Main link: char-list s       e.g. 'DCCABBBACCCD' (which is a python interpreted input of ['D','C','C','A','B','B','B','A','C','C','C','D'])
J       - range(length(s))                  [1,2,3,4,5,6,7,8,9,10,11,12]
  Œg    - group-runs(s)                     [['D'],['C','C'],['A'],['B','B','B'],['A'],['C','C','C'],['D']]
 ṁ      - mould left like right             [[1],[2,3],[4],[5,6,7],[8],[9,10,11],[12]]
     Ðf - filter keep items that would be truthy (empty is not truthy) after applying:
    Ḋ   -     dequeue (x[1:])               [    [2,3],    [5,6,7],    [9,10,11]     ]        
\$\endgroup\$
  • 2
    \$\begingroup\$ - Things I wish 05AB1E could do for 500, please. \$\endgroup\$ – Magic Octopus Urn Apr 11 '17 at 17:58
  • 1
    \$\begingroup\$ I feel more and more like this language is kind-of like cheating here. :D \$\endgroup\$ – Avamander Apr 11 '17 at 22:25
  • \$\begingroup\$ @ComradeSparklePony why the undo of the accept check? \$\endgroup\$ – Jonathan Allan Jun 2 '17 at 17:54
7
\$\begingroup\$

Brain-Flak, 57 46 bytes

{({}[({})]<(([]<>)[()])>){(<{}{}{}>)}{}<>}<>

Includes +2 for -ar

Uses 0-based indexing.

Try it online!

# While true
{

  # Subtract the second value on the stack from the first
  ({}[({})]

  # Push the height of this stack (the main stack) on the other stack
  <(([]<>)

  # Push the height of the main stack - 1
  [()])>

  # Push the difference that we calculated a second ago
  )

  # If they weren't the same character
  {

    # Pop the difference and the two stack heights
    (<{}{}{}>)

  # End if
  }

  # Pop the difference (or the 0 to get out of the if)
  {}

# Switch back to the main stack and end while
<>}

# Switch to the stack with the indexes and implicitly print
<>
\$\endgroup\$
6
\$\begingroup\$

Mathematica, 32 bytes

Union@@StringPosition[#,x_~~x_]&

Pure function which returns the 1-indexed positions of characters adjacent to an identical character.

Explanation:

StringPosition["string","sub"] gives a list of the starting and ending character positions at which "sub" appears as a substring of "string". x_~~x_ is a StringExpression which matches two adjacent, identical characters. For example, StringPosition["ABCDDDCBA",x_~~x_] gives {{4, 5}, {5, 6}}. Applying Union joins the lists, sorts, and deletes duplicates.

\$\endgroup\$
5
\$\begingroup\$

Brain-Flak, 69, 59, 56 bytes

{({}[({})]<(())>){((<{}{}>))}{}{([{}]([]<>))(<>)}{}}<>

Try it online!

+2 bytes for the -ar flags which enables ASCII input and reverses the stack.

Uses 0-based indexing. Saved 10 bytes by reducing my push-pop redundancy. Saved another 4 bytes by switching from 1 to 0-based indexing.

This is pretty much the only string based challenge that brain-flak is good at. That's because brain-flak is great at comparing consecutive characters, even though it's horrendous at string processing in general. Here is readable version of the code with comments to explain how it works:

#While True
{

    #Determine if top two are equal
    ({}[({})]<(())>){((<{}{}>))}{}

    #If so
    {

        #Pop the one, and negate it's value (giving us -1)
        ([{}]

        #Push stack height over
        ([]<>)

        #Then push stack height plus the negated pop (-1)
        ) 

        #Push a zero back onto the main stack
        (<>)

    #Endwhile
    }

    #Pop the zero
    {}

#Endwhile
}

#Toggle back, implicitly display
<>
\$\endgroup\$
  • \$\begingroup\$ A little friendly competition :) \$\endgroup\$ – Riley Apr 11 '17 at 18:36
  • \$\begingroup\$ @riley fixed! (And still one byte shorter :P) \$\endgroup\$ – DJMcMayhem Apr 11 '17 at 18:39
  • \$\begingroup\$ I always forget about -r. That brings me down to 46. \$\endgroup\$ – Riley Apr 11 '17 at 18:40
5
\$\begingroup\$

Brachylog, 19 bytes

l⟦k:?z{sĊtᵐ=∧Ċ∋h}ᶠd

Try it online!

Explanation

Brachylog is usually terrible with indexes, which again shows here.

If false. is an acceptable output in cases where there are no adjacent characters, then this would be 1 byte less by replacing ᶠd by .

l⟦k                      The list [0, …, length(Input) - 1]
   :?z                   Zip the Input with this list
      {         }ᶠd      Find with no duplicates:
            ∧Ċ∋h           The heads of each element of Ċ = [A, B] (i.e. the indexes)…
        Ċtᵐ=               …where the tails of both A and B are equal (i.e. the letters)…
       sĊ                  …and where Ċ = [A, B] is a substring of the Input
\$\endgroup\$
4
\$\begingroup\$

Octave, 35 bytes

@(s)unique([x=find(~diff(+s)),x+1])

Try it online!

Similar to my MATL answer. Here unique automatically sorts . The input to diff must be converted to double, which is done by the unary +.

\$\endgroup\$
4
\$\begingroup\$

Cubix, 37 32 31 29 28 bytes

Thanks to ETHProductions for pointing me in the direction of a three-byte saving

$uO@(;Usoi?-!w>;.....S_o\;#O

Try it here! Note that the output indices are 1-based and not in ascending order.

Expanded:

      $ u O
      @ ) ;
      U s o
i ? - ! w > ; . . . . .
S _ o \ ; # O . . . . .
. . . . . . . . . . . .
      . . .
      . . .
      . . .

Explanation

This works by reading the input character by character. To compare two characters, we simply subtract the their character codes, and if the result is 0, we print the current length of the stack, a space, the current length of the stack - 1 and another space. Then we clean up the stack a bit, and we start with the read loop again. If the end of the input string is reached, the program stops.

\$\endgroup\$
  • \$\begingroup\$ Hmm, if you can keep the stack fairly clean, you may be able to use # to get the length of the stack when you need it. (Also, LOL'ed at the ;_; in the code ;) ) \$\endgroup\$ – ETHproductions Apr 15 '17 at 14:52
  • \$\begingroup\$ A basic example (probably not fully golfed); ethproductions.github.io/cubix/… (Note: it's 1-indexed, not 0-indexed) \$\endgroup\$ – ETHproductions Apr 15 '17 at 15:04
  • \$\begingroup\$ Thanks for the reminder. I golfed one byte of your version and added that. I might be able to get anoter byte or two off... \$\endgroup\$ – Luke Apr 15 '17 at 20:54
  • \$\begingroup\$ Idea: what if you did !$w instead of !w and moved part of the fifth row logic to the fourth row? (Can't try right now because I'm heading out the door) \$\endgroup\$ – ETHproductions Apr 15 '17 at 21:22
  • \$\begingroup\$ I also thought of that, but I don't think it will save many bytes. I'll try it though. \$\endgroup\$ – Luke Apr 16 '17 at 6:54
3
\$\begingroup\$

C, 75 bytes

i;f(char*s){for(i=0;*s;++s,++i)if(s[1]==*s|(i&&s[-1]==*s))printf("%d ",i);}

Uses spaces as delimiters. (A trailing comma doesn't look too good.)

Try it online!

\$\endgroup\$
3
\$\begingroup\$

C#, 115 bytes


Golfed

i=>{var o="";for(int x=1,l=i.Length;x<=l;x++)o+=(x<l&&i[x]==i[x-1])||(x>1&&i[x-1]==i[x-2])?(x-1)+" ":"";return o;};

Ungolfed

i => {
   var o = "";

   for( int x = 1, l = i.Length; x <= l; x++ )
      o += ( x < l && i[ x ] == i[ x - 1 ] ) || ( x > 1 && i[ x - 1 ] == i[ x - 2 ] )
         ? ( x - 1 ) + " "
         : "";

   return o;
};

Ungolfed readable

i => {
   // List of positions
   var o = "";

   // Cycle through the string
   for( int x = 1, l = i.Length; x <= l; x++ )
      // Check if 'x' is below the string length
      //    and if the current and previous char are the same...
      //    ... or if 'x' is beyong the string length
      //    and the 2 previous chars are the same.
      o += ( x < l && i[ x ] == i[ x - 1 ] ) || ( x > 1 && i[ x - 1 ] == i[ x - 2 ] )

         // If true, add the index to the list of positions...
         ? ( x - 1 ) + " "

         // ...otherwise add nothing
         : "";

   // Return the list of positions.
   return o;
};

Full code

using System;
using System.Collections.Generic;

namespace Namespace {
   class Program {
      static void Main( String[] args ) {
         Func<String, String> f = i => {
            // List of positions
            var o = "";

            // Cycle through the string
            for( int x = 1, l = i.Length; x <= l; x++ )
               // Check if 'x' is below the string length
               //    and if the current and previous char are the same...
               //    ... or if 'x' is beyong the string length
               //    and the 2 previous chars are the same.
               o += ( x < l && i[ x ] == i[ x - 1 ] ) || ( x > 1 && i[ x - 1 ] == i[ x - 2 ] )

                  // If true, add the index to the list of positions...
                  ? ( x - 1 ) + " "

                  // ...otherwise add nothing
                  : "";

            // Return the list of positions.
            return o;
         };

         List<String>
            testCases = new List<String>() {
               "ABCDCABCD",
               "AABBCCDD",
               "ABCDDDCBA",
               "",
               "A",
               "AA",
               "AAA",
         };

         foreach( String testCase in testCases ) {
            Console.WriteLine( $"{testCase}\n{f( testCase )}\n" );
         }

         Console.ReadLine();
      }
   }
}

Releases

  • v1.0 - 115 bytes - Initial solution.

Notes

Nothing to add

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

Jelly, 8 bytes

=2\T’œ|$

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Hmm, exactly the same algorithm I tried, though mine was slightly longer: Ṗ=ḊTµ2Ḷ+€ \$\endgroup\$ – ETHproductions Apr 15 '17 at 15:20
2
\$\begingroup\$

k, 18 bytes

{?,/-1 0+/:&:=':x}

Examples:

k){?,/-1 0+/:&:=':x}"AABCDDDCBAA"
0 1 4 5 6 9 10
k){?,/-1 0+/:&:=':x}"ABCDCBA"
()

Translation to q is easier to understand:

{distinct raze -1 0+/:where not differ x}
\$\endgroup\$
  • \$\begingroup\$ This was my initial solution too! :D \$\endgroup\$ – zgrep Apr 13 '17 at 12:41
2
\$\begingroup\$

JavaScript, 52 bytes

Thanks @Neil for golfing off 1 byte

x=>x.map((a,i)=>a==x[++i-2]|a==x[i]&&i).filter(a=>a)

Receives input as a 0-indexed array of characters
Returns output as a 1-indexed array

Explanation

x.map()

For each character in the string

(a,i)=>(a==x[++i-2]|a==x[i])*i

If it is equal to the previous character or the next character, return the index+1 otherwise do not return (leaves undefined in the array)

.filter(a=>a)

Remove all undefined elements from the resulting array

Try it online!

\$\endgroup\$
  • \$\begingroup\$ Would &&i save a byte over (...)*i? \$\endgroup\$ – Neil Apr 11 '17 at 21:13
  • \$\begingroup\$ @Neil && is faster than |, which would result in it always returning i \$\endgroup\$ – fəˈnɛtɪk Apr 11 '17 at 21:15
  • \$\begingroup\$ 0|0&&6 is 0, 1|0&&6 is 6, 0|1&&6 is 6, 1|1&&6 is 6. Isn't that what you want? \$\endgroup\$ – Neil Apr 11 '17 at 21:23
  • \$\begingroup\$ I think I was thinking I still had || instead of | \$\endgroup\$ – fəˈnɛtɪk Apr 11 '17 at 21:36
  • \$\begingroup\$ Ah yes, that would explain it. \$\endgroup\$ – Neil Apr 11 '17 at 21:38
2
\$\begingroup\$

Python 2, 55 54 bytes

m=j=0
for i in input():
 if m==i:print~-j,j,
 j+=1;m=i

Try it Online!

Outputs indices separated by spaces (note that this displays some indices twice as allowed by OP)

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

Perl 5, 37 bytes

35 bytes of code + pl flags.

s/(?<=(.))\1|(.)(?=\2)/print pos/ge

Try it online!

(?<=(.))\1|(.)(?=\2) will match either between two repeted characters ((?<=(.))\1), or before a character that is repeated ((.)(?=\2)).
Then, print pos prints the position of the match. (pos contains the index of the current match when used in a regex with /g modifier).

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

Perl 6,  66  57 bytes

*.comb.rotor(2=>-1).kv.flatmap({($^a,$a+1)xx[eq] $^b[0,1]}).squish

Try it

{m:ex/[(.)<($0|(.))>$0]{make $/.from}/».ast.sort.squish}

Try it

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

PHP, 100 Bytes

for(;$i<strlen($s=$argn);$i++)$s[$i]==$s[$i+1]||$s[$i]==$s[$i-1]&&$i?$r[$i]=+$i:0;echo join(",",$r);
\$\endgroup\$
1
\$\begingroup\$

Ruby, 51+1 = 52 bytes

Uses the -n flag.

i=0;d=[];gsub(/./){$&==$_[i+=1]?d+=[i-1,i]:0};p d&d

Try it online!

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

Batch, 139 bytes

@set/ps=
@set/ai=c=0
:l
@if %s:~,1%==%s:~1,1% set c=2
@if %c% gtr 0 echo %i%
@set/ai+=1,c-=1
@if not "%s:~1%"=="" set s=%s:~1%&goto l

Takes input on STDIN. Works by keeping track of how many numbers to print in the c variable, which is reset to 2 when a pair is detected. Note: At a cost of 6 bytes, could be hardened to work with most ASCII characters and not just ABCD.

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

C#, 89 Bytes

using System.Linq;s=>string.Join("",s.Skip(1).Select((a,i)=>a==s[i]?i+" "+(i+1)+" ":""));

If there are three or more characters in a row the indexes are repeated. Which @Comrade SparklePony allowed in the comments.

Ungolfed full program:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Namespace
{
    class Class1
    {
        static void Main(string[] args)
        {
            Func<string, string> f2 =
                s => string.Join("" ,         //Combine the results into one string
                s.Skip(1)                     //Start with the second element
                .Select(
                    (a, i) =>                 // 'a' is the current element, 'i' is the index of the element in the result of 'Skip'
                    a == s[i] ?               // therefore 's[i]' is the previous element; compare it with the current one
                    i + " " + (i + 1) + " " : //If true, return the indexes
                    ""                        //Otherwise an empty string
                ));

            var tests = new string [] {
               "ABCDCABCD",
               "AABBCCDD",
               "ABCDDDCBA",
               "ABBCDD"
            };

            foreach (var test in tests)
            {
                Console.WriteLine(test);
                Console.WriteLine(string.Join("", f2(test)));
                Console.WriteLine();
            }

            Console.ReadLine();
        }
    }
}
\$\endgroup\$
1
\$\begingroup\$

QBIC, 42 bytes

;[2,_lA||~mid$(A,a-1,1)=mid$(A,a,1)|?a-1,a

Sample output:

Command line: AADCDBBD
 1             2 
 6             7 

Explanation:

;               Get A$ from the cmd line
[2,    |        FOR a% = 2 TO
   _lA|              the length of A$
~mid$(A,a-1,1)  IF the character at index a%
=mid$(A,a,1)    equals the char at index a%-1
|               THEN
?a-1,a          PRINT both indexes, tab-separated
                Any further doubles are printed on a separate line
                The IF and FOR are closed implicitly

EDIT: QBIC now has Substring! This challenge can now be solved in 32 bytes:

;[2,_lA||~_sA,a-1|=_sA,a||?a-1,a

Where:

_s      This is the substring function; it takes 1, 2 or 3 arguments. 
        Arguments are comma-seperated, the list is delimited with |
        In this answer we see Substring take 2 arguments:
  A,    The string to take from
    a|  Starting position (note:uppercase represents strings, lowercase is for nums)
        Any omitted argument (in this case 'length to take') is set to 1.
\$\endgroup\$
0
\$\begingroup\$

k, 14 bytes

This is a function, it takes in a string, and returns a list of indices.

&{x|1_x,0}@=':

Explanation:

           =': /compare each letter to the previous, return binary list
 {       }@    
    1_x,0      /shift left
  x|           /combine shifted and unshifted with binary or
&              /get indices of 1s

Try it online!

How to use:

&{x|1_x,0}@=':"STRINGGOESHERE"
\$\endgroup\$
0
\$\begingroup\$

PHP, 70 bytes

for(;a&$c=$argn[$i];)$i++&&$argn[$i-2]==$c||$argn[$i]==$c?print$i._:0;

takes input from STDIN; run with -R.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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