green_gibbon
green_gibbon

Reputation: 33

Combine the same values in a list to display as a range

I have a list of distances associated with each compass bearing from 1 to 360 degrees, also stored as a list. I would like to condense the list so as to give ranges of bearings over which the distance is associated, e.g.

From:

bearings = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
distance = [5, 10, 15, 15, 15, 20, 20, 10, 10, 5]

To:

bearings = [1, 2, 3-5, 6-7, 8-9, 10]
distance = [5, 10, 15, 20, 10, 5]

Any ideas what sort of approach to take this on with? Thanks in advance!

Upvotes: 2

Views: 93

Answers (2)

user1717828
user1717828

Reputation: 7225

Just for fun, I tried doing this in one line with itertools.groupby. If you're writing throwaway code for data munging or something, this will do. Otherwise, I recommend breaking it out into a for loop so it's more maintainable.

from itertools import groupby

bearings = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
distance = [5, 10, 15, 15, 15, 20, 20, 10, 10, 5]

new_bearings, new_distance = zip(
    *[
        (f"{pairs[0][0]}-{pairs[-1][0]}", k) 
        if len(pairs) > 1
        else (str(pairs[0][0]), pairs[0][1])
        for k, pairs in [
            (k, list(g))
            for k, g in groupby(zip(bearings, distance), key=lambda x: x[1])
        ]
    ]
)

print(f"{new_bearings=}")
# new_bearings=('1', '2', '3-5', '6-7', '8-9', '10')

print(f"{new_distance=}")
# new_distance=(5, 10, 15, 20, 10, 5)

I hate it :-)

The idea is the inner loop is grouping by your distances and giving tuples where they're the same. You need to return (k, list(g)) because g is an iterator and you need a list for len and slicing.

Once you have the lists of tuples, the ugly string operations are to give your lower-upper notation, or just converting the first element to a string if there's only a single pair.

Upvotes: 1

Ewan Brown
Ewan Brown

Reputation: 637

By 'clumping' the distance array by repeating values we can recreate the bearings array

There is probably a more python-ic way to do this, but this is somewhere to start!

bearings = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
distance = [5, 10, 15, 15, 15, 20, 20, 10, 10, 5]

clumps = []
current_clump = []

# Clump repeating distances together
last_val = None
for i in range(len(distance)):
    current_val = distance[i]
    
    # if this element (distance) is the same as the last, add it to the current clump
    # otherwise add the current clump to our clumps list and create a new empty one
    if current_val == last_val or last_val is None:
        current_clump.append(current_val)
    else:
        clumps.append(current_clump)
        current_clump = [current_val]

    last_val = current_val

# Add the 'leftover' clump after the loop is done
clumps.append(current_clump)

# Create the output "ranged_indices" array that will have our desired ranged values
ranged_indices = []
current_indice = 0;
for i in range(len(clumps)):
    current_len = len(clumps[i])
    if current_len == 1:
        ranged_indices.append(current_indice+1)
    else:
        high_end = (current_indice+current_len)
        ranged_indices.append(str(current_indice+1)+'-'+str(high_end))

    current_indice += current_len

print(ranged_indices)
print(clumps)

Upvotes: 1

Related Questions