How to change runs of values in a column with Perl, Python or bash
Question: I want to iterate through lots of tab-delimited files and change a single
column in the following way:

ORIGINAL

    
    
    Col1    Col2    ....
    afawer  1
    asdgf   1
    aser    1
    qwerq   10
    a3awer  10
    1sdgf   11
    a55er   11
    2wu9    12
    asxwer  12
    a2dgf   13
    a1er    13
    qperq   13
    ...
    

DESIRED REPLACEMENT

    
    
    Col1    Col2    ....
    afawer  1
    asdgf   1
    aser    1
    qwerq   2
    a3awer  2
    1sdgf   3
    a55er   3
    2wu9    4
    asxwer  4
    a2dgf   5
    a1er    5
    qperq   5
    ...
    

Note that the run lengths in Col2 will vary substantially for each file, so
the lengths cannot be hard-coded. Essentially, the pattern I want to replace
is this:

> aaabbbbbccccdddd

where a, b, c and d could be any integers. The desired replacement is:

> 1112222233334444

and so on (i.e. a natural ordering of integers).

I'd like to do this with Python or Perl, or just using bash commands like
`sed` if possible.


Answer: With Python, use
[`itertools.groupby()`](http://docs.python.org/2/library/itertools.html#itertools.groupby)
to group rows on the second column, and a counter provided by
[`enumerate()`](http://docs.python.org/2/library/functions.html#enumerate):

    
    
    import csv
    from itertools import groupby
    from operator import itemgetter
    
    with open(inputfile, 'rb') as ifh, open(outputfile, 'wb') as ofh:
        reader = csv.reader(ifh, delimiter='\t')
        writer = csv.writer(ofh, delimiter='\t')
        writer.writerow(next(reader))  # copy across header
    
        for counter, (key, group) in enumerate(groupby(reader, itemgetter(1)), 1):
            for row in group:
                row[1] = counter
                writer.writerow(row)
    

This writes a new CSV file with the same data, except the second column is
replaced by a counter (starting at 1) that increments every time the original
value in column 2 changes.

