2

Clear as mud, aye? I'll start with an example...

my_list = [[4,'A4, A23, A3, A6', 'Description 1', 'Property 1'],
           [4,'B3, B35, B10, B22', 'Description 2', 'Property 2'],
           [6,'A1, A11, A10, A21, A2, A22', 'Description 3', 'Property 3']]

Should sort to:

>>>my_list:
[[6,'A1, A2, A10, A11, A21,  A22', 'Description 3', 'Property 3'] 
 [4,'A3, A4, A6, A23', 'Description 1', 'Property 1'],
 [4,'B3, B10, B22, B35', 'Description 2', 'Property 2']]

So, I first need to naturally sort the string in the second index of every sub-list, then I need to naturally sort all of the lists based on the string in the second index of sub-list. I have been banging my head against the wall on this all day, so me posting any code that I have tried would probably just lead this down the wrong track.


Perhaps my initial sample case wasn't robust enough, but this is the result I am getting based on @Ashwini's code:

[[ 1,   'C1', 'DW-00232'],
 [3,    'C11, C32, C46', 'DW-6546'],
 [7,    'C16, C17, C18, C19, C20, C21, C25', 'DW-545'],
 [5,    'C2, C3, C4, C5, C63', 'DW-7657'],
 [1,    'C26', 'DW-0056'],
 [2,    'C59, C60', 'DW-23424'],
 [5,    'C6, C13, C24, C30, C64', 'DW-5345']]

I would like the output to be as follows:

[[ 1,   'C1', 'DW-00232'],
 [5,    'C2, C3, C4, C5, C63', 'DW-7657'],
 [5,    'C6, C13, C24, C30, C64', 'DW-5345'],
 [3,    'C11, C32, C46', 'DW-6546'],
 [7,    'C16, C17, C18, C19, C20, C21, C25', 'DW-545'],
 [1,    'C26', 'DW-0056'],
 [2,    'C59, C60', 'DW-23424']]

The goal posts keep moving. Now I need to consider a case where some of the alpha-numeric combos are in parentheses. I need to ignore the parenthesis during the sort.

Example:

[[ 1, 'C1', 'DW-00232'],
 [ 7, '(C21), C16, (C7), (C18), C19, C6, C65', 'DW-545'],
 [ 5, ' C4, (C2), C3, C10, (C5)', 'DW-7657']]

Sorts to this:

[[ 1, 'C1', 'DW-00232'],
 [ 5, '(C2), C3, C4, (C5), C10', 'DW-7657'],    
 [ 7, 'C6, (C7), C16, (C18), C19, (C21), C65', 'DW-545']]

Okay, the above case was an 'easy' fix, once I inspected Ashwini's code a little closer. I added the translate statement to his natural sort function to the following, based on how he handled his key function (since that was sorting the way I wanted, it was only the per-line sort that wasn't right), as follows.

        alphanum_key = (lambda key:
                        [convert(c.translate(None, punctuation + whitespace)) for c in re.split('([0-9]+)', key)])
realityinabox
  • 593
  • 1
  • 5
  • 14

2 Answers2

1

Using the natural_sort function from this answer you can do something like this:

import re
from string import punctuation as punc, whitespace as wt
from pprint import pprint

def natural_sort(l): 
    #https://stackoverflow.com/a/4836734/846892
    convert = lambda text: int(text) if text.isdigit() else text.lower() 
    alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ] 
    return sorted(l, key = alphanum_key)

def key(seq):                                           
    convert = lambda text: int(text) if text.isdigit() else text.lower() 
    return [convert(c.translate(None, punc+wt)) for c in re.split('([0-9]+)', seq)]
... 
>>> my_list = [[ 1,   'C1', 'DW-00232'],
 [3,    'C11, C32, C46', 'DW-6546'],
 [7,    'C16, C17, C18, C19, C20, C21, C25', 'DW-545'],
 [5,    'C2, C3, C4, C5, C63', 'DW-7657'],
 [1,    'C26', 'DW-0056'],
 [2,    'C59, C60', 'DW-23424'],
 [5,    'C6, C13, C24, C30, C64', 'DW-5345']]
>>> 
>>> new_lis = [x[:1] + [", ".join(natural_sort(x[1].split(', ')))] + x[2:]
                                                                for x in my_list]
>>> new_lis.sort(key = lambda x:key(x[1]))               
>>> pprint(new_lis)
[[1, 'C1', 'DW-00232'],
 [5, 'C2, C3, C4, C5, C63', 'DW-7657'],
 [5, 'C6, C13, C24, C30, C64', 'DW-5345'],
 [3, 'C11, C32, C46', 'DW-6546'],
 [7, 'C16, C17, C18, C19, C20, C21, C25', 'DW-545'],
 [1, 'C26', 'DW-0056'],
 [2, 'C59, C60', 'DW-23424']]
>>> 
Community
  • 1
  • 1
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • It appears that the first level of natural sort is working correctly, but the second level is not. Item Item Reference 1 1 A1 2 1 C1 3 3 C11, C32, C46 4 1 C14 5 1 C15 6 7 C16, C17, C18, C19, C20, C21, C25 7 5 C2, C3, C4, C5, C63` – realityinabox Mar 07 '14 at 20:13
  • @realityinabox Post the data in question body not in comments. – Ashwini Chaudhary Mar 07 '14 at 20:24
  • 1
    An alternative to hand-writing a natural_sort function is to use the `natsort` module. – SethMMorton Jan 15 '15 at 03:58
0

The default for sort is to use the builtin cmp to compare elements I think, but you can do, for example:

my_list.sort(key = lambda x: x[1])

That will instruct it to use the first element of every sublist as the comparison key

Edit: without lambdas...

from operator import itemgetter
my_list.sort(key = itemgetter(1))
Ricardo Cárdenes
  • 9,004
  • 1
  • 21
  • 34