# Chunk + Enumerate a list of digits

I have a list of decimal digits:

4, 4, 4, 7, 7, 9, 9, 9, 9, 2, 2, 2, 4, 4

The list of decimal digits are known as items. We can form "chunks" from these items by grouping together identical and adjacent numbers. I want to assign each chunk a unique number, starting from 1, and increasing by 1 in the order the chunks appear in the original list. So, the output for the given example would look like this:

1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 5, 5

## Input format

A list of digits. (0-9) You may use your language built-ins to read this list however you want. Encoding: ASCII

# Output format

A series of decimal numbers, separated by a delimiter. Your program must always use the same delimiter. The delimiter must be longer than 0 bits. Encoding: ASCII

Standard loopholes apply.

• Any particular reason for the strict input and output format? – Unrelated String Aug 13 at 21:26
• @UnrelatedString Hmm, I shall loosen them. – noɥʇʎԀʎzɐɹƆ Aug 13 at 21:27
• The IO is still rather strict. Can't you just say "input and output is as a list" and let the site defaults take care of it for you? – Jo King Aug 14 at 3:35
• Can we assume the list is non-empty? – Jo King Aug 14 at 4:14
• A list by definition has delimiters already. That's why it's a list. I also don't understand what you mean by You may use your language built-ins to read this list however you want.. Does that mean we have to include a string to list converter in our submission? And are we allowed to output as a list? – Jo King Aug 15 at 0:47

# Python 3.8 (pre-release), 41 bytes

lambda l,n=0:[n:=n+(l!=(l:=x))for x in l]


Try it online!

Praise the magic walrus := of assignment expressions.

# Python 2, 42 bytes

n=0
for x in input():n+=x!=id;id=x;print n


Try it online!

• Hmm, how long would this be in Pyth? – noɥʇʎԀʎzɐɹƆ Aug 14 at 0:05
• Huh, I avoided id because it's 2 bytes long... – Erik the Outgolfer Aug 14 at 7:54
• Oof nice idea of id – U10-Forward Aug 14 at 12:23

# APL (dzaima/APL), 7 bytesSBCS

Anonymous tacit prefix function. Prints space-separated.

+\1,2≠/


Try it online!

2≠/ pair-wise inequality

1, prepend 1

+\ cumulative sum

# Python 2, 44 bytes

l=input()
n=0
for i in l:n+=i!=l;l=i;print n


Try it online!

# Jelly, 6 5 bytes

ŒɠµJx


Try it online!

Saved one byte thanks to UnrelatedString!

Inputs and outputs as array's (with opening/closing brackets)

## How it works

ŒɠµJx - Main link, takes one argument:                       [7, 7, 5, 5, 5, 1]
Œɠ    - Get the lengths of consecutive elements:             [2, 3, 1]
µ   - Call these lengths A
J  - range(length(A))                                     [1, 2, 3]
x - Repeat each element by the corresponding value in A: [1, 1, 2, 2, 2, 3]


# Wolfram Language (Mathematica), 29 bytes

Join@@(i=1;0#+i++&/@Split@#)&


Try it online!

# 05AB1E, 5 bytes

¥Ā.¥>


Try it online!

• Minor 5-bytes alternative: ¥Ā could also be üÊ. – Kevin Cruijssen Aug 14 at 6:55
• 4 bytes – Grimy Aug 14 at 12:03

f(a:t)=1:map(+sum[1|a/=t!!0])(f t)
f e=e


Try it online!

# Pyth, 13 11 bytes

s.e*]hkhbr8


Try it online!

         r8  # Run-length encode (implicit argument is the input) (-> [[frequency, char], ...]
.e          # Enumerated map (current element is b, index is k) over rQ8
*]hk      # [ k+1 ] *
hb    #           b[0]
s            # Reduce list on + ([a]+[b] = [a,b])


-2 bytes thanks to Mr. Xcoder

• hMsM._+0nVt for -2 bytes. – Mr. Xcoder Aug 14 at 7:56
• Or if you want to keep your approach, rQ8 is the same as r8 and .n can be s for -2 as well – Mr. Xcoder Aug 14 at 7:57
• Ah nice, the docs didn't mention what functions take an implicit Q – ar4093 Aug 14 at 8:39

# Scala, 75 bytes

s=>s.scanLeft(("",0))((x,y)=>(y,x._2+(if(x._1!=y)1 else 0))).tail.map(_._2)


Try it online!

If input and output must be comma separated String (and not List) then 102 bytes.

s=>s.split(", ").scanLeft(("",0))((x,y)=>(y,x._2+(if(x._1!=y)1 else 0))).tail.map(_._2).mkString(", ")


# Jelly, 5 bytes

nƝÄŻ‘


Try it online!

I initially aimed for a 4-byter (the same program but without the Ż) but then quickly realized that a 1 had to be prepended every time due to an oversight... Even though there is another 5-byter in Jelly, I'll actually keep this because it uses a different method.

For each pair of neighbouring items of the input list $$\L\$$, test if $$\L_i\ne L_{i+1}, \forall 1\le i<|L|\$$ and save these results in a list. Then take the cumulative sum of this list and increment them by 1 to match the chunk indexing system. TL;DR. Whenever we encounter different neighbouring items, we increment the chunk index by 1.

# R, 33 bytes

function(x)cumsum(c(1,!!diff(x)))


Try it online!

Uses the same cumulative sum method as Luis Mendo and others.

# JavaScript (ES6), 30 bytes

Takes input as an array of integers.

a=>a.map(p=n=>i+=p!=(p=n),i=0)


Try it online!

### Commented

a =>                // a[] = input array
a.map(p =         // initialize p to a non-numeric value
n =>              // for each value n in a[]:
i +=            //   increment i if:
p != (p = n), //     p is not equal to n; and update p to n
)                 // end of map()


while(''<$d=$argv[++$x])echo$i+=$argv[$x-1]!=$d,' ';  Try it online! Input via command line, output to STDOUT. Thx to @Night2 for the pesky '0' == 0 comparison bugfix! • @Night2 good catch! Updated and fixed. Thx! – 640KB Aug 15 at 17:42 # Japt v2.0a0, 9 bytes £T±A¦(A=X  Try it # Add++, 23 bytes D,f,@*,BGd€bL$bLRz€¦XBF


Try it online!

## How it works

D,f,@*,     - Define a function, f, that takes one argument:  [7 7 5 5 5 1]
BG   - Group neighbouring elements together:           [[[7 7] [5 5 5] [1]]]
d    - Duplicate:                                      [[[7 7] [5 5 5] [1]] [[7 7] [5 5 5] [1]]]
€bL  - Get the length of each:                         [[[7 7] [5 5 5] [1]] [2 3 1]]
$bLR - Length, then range of length: [[2 3 1] [1 2 3]] z - Zip together: [[2 1] [3 2] [1 3]] €¦X - Reduce each by repetition: [[1 1] [2 2 2] [3]] BF - Flatten: [1 1 2 2 2 3] - Due to the * in the function definition, return the whole stack: [1 1 2 2 2 3]  # Japt, 8 7 bytes ä¦Ug)åÄ  Try it # Retina 0.8.2, 34 bytes \b\d+\b(?<=(\b(\3|(\d+))\D*)*)$#3


Try it online! Explanation:

\b\d+\b


Match each number in turn.

(?<=(...)*)


Start looking backwards for as many matches as possible. (The next entries will be in right-to-left order as that's how lookbehind works.)

\D*


Skip the separators.

(\3|(\d+))


Try to match the same number as last time, but failing that, just match any number, but remember that we had to match a new number.

\b


Ensure the whole number is matched.

\$#3


Count the number of new numbers.

# Stax, 10 bytes

▓ª2ªmD?Ä╧╖


Run and debug it

The output uses space as a delimiter. The input follows the precise specifications using commas as separators, and now enclosing braces.

# C (gcc), 62 61 bytes

This is one of the few entries I've done where a complete program is shorter than a function submission!

On the first pass, I don't care about the previous value, so I get to rely on the fact that argv is a pointer to somewhere and is extremely unlikely to be between [0..9]!

s;main(i,j){for(;~scanf("%d,",&i);j=i)printf("%d ",s+=j!=i);}


Try it online!

# Scala, 114 bytes

s.split(", ").zipWithIndex.scan(s.head,0){(a,b)=>if(a._1==b._1)a else b._1->(a._2+1)}.tail.unzip._2.mkString(", ")


Try it online!

# C (gcc), 62 bytes

f(_,l)int*_;{printf("%d ",l=--l?f(_,l)+(_[l]!=_[l-1]):1);_=l;}


Try it online!

A function that takes the list and its length as arguments.

### C (gcc), 60 bytes

f(_,l)int*_;{_=printf("%*d",--l?f(_,l)+(_[l]!=_[l-1]):2,0);}


Try it online!

Outputs in unary, delimited by 0s

# x86-16, 12 bytes

Unassembled listing:

        NUM_LOOP:

Input is byte array at SI, length in CX. Output is byte array at DI. Of course, this is if default I/O rules apply now.
Example: SI = 120H, DI = 130H