34
\$\begingroup\$

Given an input of a string consisting entirely of qs representing quarter notes and es representing eighth notes, output the indices of the quarter notes that are syncopated.

Syncopation is complex, but for the purposes of this challenge, our definition of "syncopated" will be very simple: a quarter note that starts on the "off-beat"—that is, the beats counted as "and" in n/4 time.

This may alternatively be defined as any quarter note that is preceded by an odd number of eighth notes. For example, the notes marked with * below are considered syncopated, and their indices are also shown:

eqqeqqeqqe
 **    **
 12    78
Output: 1 2 7 8

The input will always consist of a whole number of measures in 4/4 time (a quarter note is a quarter of a measure, and an eighth note is an eighth of a measure). (The input will also never be empty.) Output can either be a single string with elements separated by any delimiter that does not contain numbers or an array/list/etc. The output may be 1-based (i.e. the first index is 1 instead of 0) if you wish, and it may also be in any numeric base (unary, decimal, etc.).

Since this is , the shortest code in bytes wins.

Test cases:

In                        Out
-----------------------------------------------
eqqqe                     1 2 3
qeqeq                     2
qqqeqqeeeeqeqeqeqqeqqeqq  4 5 10 14 19 20
eeeeeqeeqeeqqqqeqeqeeqe   5 8 11 12 13 14 18 21
qqqq                      <none>
eeeeeeee                  <none>
\$\endgroup\$
7
  • 1
    \$\begingroup\$ Can output be 1-based? \$\endgroup\$
    – Luis Mendo
    Jan 15, 2016 at 22:15
  • 1
    \$\begingroup\$ Could you do a worked example to show how the indices work? \$\endgroup\$ Jan 15, 2016 at 22:16
  • 1
    \$\begingroup\$ @LuisMendo Sure, if it makes your code shorter. \$\endgroup\$
    – Doorknob
    Jan 15, 2016 at 22:24
  • \$\begingroup\$ @PeterTaylor Okay, is something like that what you were thinking of? \$\endgroup\$
    – Doorknob
    Jan 15, 2016 at 22:25
  • \$\begingroup\$ Can the input be a string including the quote signs? 'eqqqe' instead of eqqqe \$\endgroup\$
    – Luis Mendo
    Jan 15, 2016 at 23:38

17 Answers 17

12
\$\begingroup\$

Jelly, 12 9 bytes

=“e”µ<^\O

As a program, the above code requires quotes around the input. Since that is not allowed, this is a function submission. The output is 1-based. Try it online!

How it works

=“e”µ<^\O    Monadic link. Argument: s (string)

=“e”         Check each character for equality with 'e'. Yields a Boolean array.
    µ        Start a new, monadic chain.
      ^\     Compute the array of partial reductions by XOR, i. e., the parities
             of all prefixes of the Boolean array.
     <       Check if the Booleans are strictly smaller than the parities.
             A truthy outcome indicates an off-beat quarter note.
        O    Yield all indices of 1's.

Update

The above code doesn't work anymore in the latest version of Jelly, since we need a character e, but “e” yields a string. Fixing that saves a byte, for a total of 8 bytes.

=”eµ<^\O

This works as a full program. Try it online!

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

Ruby, 46

i=e=0
gets.bytes{|n|e^=n
e&4|n>114&&p(i)
i+=1}

Input to stdin. Output to stdout, newline separated.

Commented

i=e=0               #i keeps index, e keeps track of 8ths.
gets.bytes{|n|      #iterate through bytes in the input
e^=n                #xor e with input. We're interested in the 4's bit, which is only affected by ascii e, not ascii q
e&4|n>114&&p(i)     #e&4 evaluates to 4 or 0. OR with n and if the value is greater than ascii code for q, print index
i+=1}               #increment index
\$\endgroup\$
6
\$\begingroup\$

JavaScript ES7, 50 48 bytes

Pretty short for JS, if you ask me. [for...of] syntax, basically combined map and filter, comes in handy for this challenge.

s=>[for(c of(i=f=0,s))if(++i&&c>'e'?f%2:f++&0)i]

Defines an anonymous function that outputs a 1-indexed array.

Test snippet

This uses an ungolfed, un-ES7'd version of the code.

a = function(s) {   // Create a function a that takes in a parameter s and does these things:
  var r = [],       // Set variable r to an empty array,
  i = 0, f = 0;     // i to 0, and f to 0.
  for(c of s) {     // For each character c in s:
    i++;            //  Increment i by 1.
    if(             //  If
      c == 'q' ?    //   if c == 'q',
      f%2 === 1 :   //    f is even; otherwise,
      f++ && false) //    increment f and don't execute this:
      r.push(i);    //   Add i to the end of r.
  } return r;       // Return r.
}
<input type="text" value="eqqqe" id=O />
<button onclick="P.innerHTML='['+a(O.value)+']'">Try it</button>
<p id=P />

\$\endgroup\$
3
  • 3
    \$\begingroup\$ Very good explanation! And also a great example of how to use ES7's new [For...of] 👍 \$\endgroup\$ Jan 16, 2016 at 5:57
  • \$\begingroup\$ So, do we need a new question, "Tips for Golfing in ECMAScript 7"? \$\endgroup\$
    – Neil
    Jan 17, 2016 at 22:51
  • \$\begingroup\$ @Neil I tried updating the ES6 post to ES6/7, but the OP rolled back the edit. In the meantime, there is this: codegolf.stackexchange.com/a/61489/42545 \$\endgroup\$ Jan 17, 2016 at 22:59
5
\$\begingroup\$

J, 20 19 17 bytes

=&'e'(I.@:<~:/\@)

Thanks to randomra for saving a byte, and to Dennis for saving two. This is an unnamed monadic verb, used as follows:

  f =: =&'e'(I.@:<~:/\@)
  f 'eqqqe'
1 2 3

Try it here.

Explanation

=&'e'(I.@:<~:/\@)
=&'e'               Replace every 'e' with 1, other chars with 0
     (         @)   Apply the verb in parentheses to the resulting 0-1 vector
           ~:/\     Cumulative reduce with XOR (parity of 'e'-chars to the left)
          <         Element-wise less-than with original vector
      I.@:          Positions of 1s in that vector
\$\endgroup\$
0
5
\$\begingroup\$

GNU grep, 3+17=20 3 + 15 = 18 bytes

The program requires the options boP. The code is

q(?!(q|eq*e)*$)

Save it as synco, then run as grep -boPf synco.

The output separator is :q followed by a newline. E.g. the output for eqqqe is

1:q
2:q
3:q

The meanings of the flags are:

  • P: Use PCRE regexes.
  • o: This means to print only the part of the line that matches the regular expression, but that's not why it's important. o is used because it has the effect of allowing multiple matches per line.
  • b: Print the offset in bytes of the beginning of each match from the beginning of the file.

The pattern checks that there is not an even number of eighth notes after a quarter note.

\$\endgroup\$
4
  • \$\begingroup\$ Does grep qualify as a language in its own right? Regardless, +1 for a great answer \$\endgroup\$ Jan 15, 2016 at 23:22
  • \$\begingroup\$ @DigitalTrauma I don't see why not... It can use PCRE regexes, so it should be Turing-complete at least, and can execute code from a file as shown here. \$\endgroup\$
    – feersum
    Jan 15, 2016 at 23:23
  • \$\begingroup\$ I was under the impression that PCRE is not proven to be Turing complete. Regardless, your expression meets the requirement, so I'm OK with it, but there may be others with complaints on theoretical grounds. \$\endgroup\$ Jan 16, 2016 at 0:04
  • \$\begingroup\$ @DigitalTrauma Huh, seems I was deluded about the Turing-completeness thing. \$\endgroup\$
    – feersum
    Jan 16, 2016 at 0:13
5
\$\begingroup\$

MATL, 12 14 16 bytes

j101=tYs2\<f

Thanks to Dennis for removing 2 bytes (and for hosting MATL in his awesome online platform!)

This uses current version (9.3.0) of the language/compiler.

Input and output are through stdin and stdout. The result is 1-based.

Example:

>> matl j101=tYs2\<f
> eeeeeqeeqeeqqqqeqeqeeqe
6  9 12 13 14 15 19 22

Or try it online!

Explanation

j             % input string
101=          % vector that equals 1 at 'e' characters and 0 otherwise
t             % duplicate
Ys2\          % cumulative sum modulo 2
<             % detect where first vector is 0 and second is 1
f             % find (1-based) indices of nonzero values
\$\endgroup\$
0
3
\$\begingroup\$

Python 2, 94 85 79 75 66 bytes

EDIT: Thanks Doorknob and Alex A.

EDIT: Thanks Alex A.

EDIT: Now using input() so the input must be a string with the quotes.

EDIT: Thanks Zgarb for recommending me to use enumerate.

Simply counts number of e's and if q, check if e count is odd, then print index.

e=0
for j,k in enumerate(input()):
 if"q">k:e+=1
 elif e%2:print j

Try it here

\$\endgroup\$
6
  • \$\begingroup\$ You can replace the second if ... with just an else to save 8 bytes. \$\endgroup\$
    – Doorknob
    Jan 15, 2016 at 22:13
  • \$\begingroup\$ You can also remove the space after print for 1 byte \$\endgroup\$
    – Alex A.
    Jan 15, 2016 at 22:14
  • \$\begingroup\$ I think you can change the else: if e%2: to just elif e%2:. \$\endgroup\$
    – Alex A.
    Jan 15, 2016 at 22:16
  • \$\begingroup\$ You can save one more byte by checking i[j]<"q" rather than i[j]=="e". \$\endgroup\$
    – Alex A.
    Jan 15, 2016 at 22:18
  • 2
    \$\begingroup\$ @TanMath I asked Doorknob because it would save me 2 bytes to take an input with quotes. But it can't be done \$\endgroup\$
    – Luis Mendo
    Jan 16, 2016 at 2:03
3
\$\begingroup\$

Haskell, 58 51 bytes

f x=[i|(i,'q')<-zip[0..]x,odd$sum[1|'e'<-take i x]]

Usage example: f "eeeeeqeeqeeqqqqeqeqeeqe" -> [5,8,11,12,13,14,18,21].

Go through the list and output the current index i for every char 'q' if there's an odd number of 'e's before it.

\$\endgroup\$
3
+100
\$\begingroup\$

APL (Dyalog Classic), 12 bytes

(⍸~×≠\)'e'∘=

Try it online!

Outputs 1-indexed.

Explanation:

       'e'∘=    ⍝ Map each element to whether it is equal to 'e'
(     )         ⍝ Then apply the train
  ~             ⍝ Not the array into indexes of 'p'
   ×            ⍝ Multiply this by
    ≠\          ⍝ The cumulative reduction by inequality 
 ⍸              ⍝ And get the indexes of the ones in the array
\$\endgroup\$
1
  • 2
    \$\begingroup\$ It's generally recommended to use Unicode/Extended over Classic. \$\endgroup\$
    – Razetime
    Sep 12, 2020 at 5:03
2
\$\begingroup\$

Minkolang 0.15, 28 bytes

(o"q"=7&z1+$z8!z2%,2&iN$I$).

Try it here.

Explanation

(                        Open while loop
 o                       Read in character from input
  "q"                    Push the character "q"
     =                   1 if the top two items on stack are equal, 0 otherwise
      7&                 Pop and jump 7 spaces if truthy

        z                Push register value on stack
         1+              Add one
           $z            Pop top of stack and store in register
             8!          Jump eight spaces

        z                Push register value on stack
         2%              Modulo by 2
           ,             boolean not
            2&           Pop and jump two spaces if truthy
              i          Push loop counter
               N         Output as number

                $I       Push length of input
                  $).    Close while loop when top of stack is 0 and stop.
\$\endgroup\$
2
\$\begingroup\$

C (function), 65

Thanks to @Dennis for the extra golfing!

i,n;f(char*m){for(i=n=0;*m;i++)*m++&4?++n:n%2?printf("%d ",i):0;}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ I think i,n;f(char*m){for(i=n=0;*m;m++,i++)*m&4?++n:n%2?printf("%d ",i):0;} should work. \$\endgroup\$
    – Dennis
    Jan 16, 2016 at 3:15
2
\$\begingroup\$

Python 3, 109 95 80 90 88 76 68 67 66 64 bytes

Counts the number of qs and es and adds the index of the current q if the number of preceding es is odd.

Edit: Now it prints a list of the indices of s that are q and have an odd number of es preceding them. Eight bytes saved thanks to Doorknob and two more thanks to feersum.

lambda s:[x for x,m in enumerate(s)if("e"<m)*s[:x].count("e")%2]

Ungolfed:

def f(s):
    c = []
    for index, item in enumerate(s):
        if item == "q":
            if s[:index].count("e")%2 == 1:
                c.append(index)
    return c
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Couldn't you make this a lambda to make the input and print statements unnecessary? \$\endgroup\$
    – Doorknob
    Jan 15, 2016 at 22:35
  • \$\begingroup\$ It should be shorter to use enumerate rather than range(len(.... \$\endgroup\$
    – feersum
    Jan 15, 2016 at 23:00
2
\$\begingroup\$

JavaScript ES6, 63 60 58 bytes

x=>[...x].map((e,i)=>e>'e'?n%2&&a.push(i):n++,a=[],n=0)&&a

Anonymous function that outputs an array. Thanks to user81655 for saving two bytes. Here is an ungolfed version that uses better supported syntax.

f=function(x) {
  a=[] // Indeces of syncopated notes
  n=0 // Number of e's encountered so far
  x.split('').map(function(e,i) { // For each letter...
    e>'e'? // If the letter is q...
      n%2&& // ...and the number of e's is odd...
        a.push(i): // ...add the current index to the array
      n++ // Otherwise, it is e so increment the counter
  })
  return a
}

run=function(){document.getElementById('output').textContent=f(document.getElementById('input').value)};document.getElementById('run').onclick=run;run()
<input type="text" id="input" value="qqqeqqeeeeqeqeqeqqeqqeqq" /><button id="run">Run</button><br />
<samp id="output"></samp>

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

Mathematica, 76 bytes

Flatten[Range[#+1,#2-1]&@@@StringPosition[#,"e"~~"q"..~~"e",Overlaps->1<0]]&

Something interesting I noticed. All of the syncopated parts are of form eqqq..qqe, so I just detect those and give the indices of the qs.

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

Japt, 29 23 21 bytes

Not non-competing anymore!

0+U ¬®¥'e} å^ ä© m© f

Try it online!

How it works

         // Implicit: U = input string, e.g.    "eqqeqeq"
0+U      // Add a 0 to the beginning.           "0eqqeqeq"
¬        // Split into chars.                   ['0,'e,'q,'q,'e,'q,'e,'q]
®¥'e}    // Map each item X to (X == 'e).       [F, T, F, F, T, F, T, F]
å^       // Cumulative reduce by XOR'ing.       [0, 1, 1, 1, 0, 0, 1, 1]
ä©       // Map each consecutive pair with &&.  [0, 1, 1, 0, 0, 0, 1]
m©       // Map each item with &&. This performs (item && index):
         //                                     [0, 1, 2, 0, 0, 0, 6]
f        // Filter out the falsy items.         [   1, 2,          6]
         // Implicit output                     [1,2,6]

Non-competing version, 18 bytes

U¬m¥'e å^ ä©0 m© f

Try it online!

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

Befunge, 43 bytes

:~:0\`#@_5%2/:99p1++\>2%#<9#\9#.g#:*#\_\1+\

Try it online!

Explanation

We start with two implicit zeros on the stack: the note number, and a beat count.

:               Make a duplicate of the beat count.
~               Read a character from stdin.
:0\`#@_         Exit if it's less than zero (i.e. end-of-file).
5%2/            Take the ASCII value mod 5, div 2, translating q to 1 and e to 0.
:99p            Save a copy in memory for later use.
1+              Add 1, so q maps to 2 and e to 1.
+               Then add that number to our beat count.
\               Get the original beat count that we duplicated at the start.
2%              Mod 2 to check if it's an off-beat.
99g*            Multiply with the previously saved note number (1 for q, 0 for e).
_               Essentially testing if it's a quarter note on an off-beat.
       \.:\     If true, we go turn back left, get the beat count, and output it.
         >2     Then push 2 onto the stack, and turn right again.
2%              That 2 modulo 2 is just zero.
99g*            Then multiplied by the saved note number is still zero.
_               And thus we branch right on the second pass.
\1+\            Finally we increment the note number and wrap around to the start again.
\$\endgroup\$
0
\$\begingroup\$

Japt, 11 bytes

ðÈø¬?Tu:!°T

Try it

\$\endgroup\$

Your Answer

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

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