Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reverse a list in python based on condition

I want to sort this list in a way that .log should be the first file and .gz file should be in a descending order

my_list = [
     '/abc/a.log.1.gz',
     '/abc/a.log',
     '/abc/a.log.30.gz',
     '/abc/a.log.2.gz',
     '/abc/a.log.5.gz',
     '/abc/a.log.3.gz',
     '/abc/a.log.6.gz',
     '/abc/a.log.4.gz',
     '/abc/a.log.12.gz',
     '/abc/a.log.10.gz',
     '/abc/a.log.8.gz',
     '/abc/a.log.14.gz',
     '/abc/a.log.29.gz'
]

expected_result:

my_list = ['/abc/a.log',
        '/abc/a.log.30.gz',
        '/abc/a.log.29.gz',
        '/abc/a.log.29.gz',
        '/abc/a.log.14.gz',
        '/abc/a.log.12.gz',
        '/abc/a.log.10.gz',
        '/abc/a.log.8.gz',
        '/abc/a.log.6.gz',
        '/abc/a.log.5.gz',
        '/abc/a.log.4.gz',
        '/abc/a.log.3.gz',
        '/abc/a.log.2.gz'
        '/abc/a.log.1.gz']

reversed(mylist) is also not getting me the desired solution.

like image 654
user15051990 Avatar asked Jan 29 '19 20:01

user15051990


People also ask

How do I reverse a list order in Python?

In order to reverse the original order of a list, you can use the reverse() method. The reverse() method is used to reverse the sequence of the list and not to arrange it in a sorted order like the sort() method. reverse() method reverses the sequence of the list permanently.

How do you reverse a list without using slicing in Python?

Another way to reverse python list without the use of any build-in methods is using loops. Create an empty list to copy the reversed elements. In the for loop, add the iterator as a list element at the beginning with the new list elements. So in that way, the list elements will be reversed.

How do you reverse a list quickly in Python?

You can reverse a list in Python using the built-in reverse() or reversed() methods. These methods will reverse the list without creating a new list. Python reverse() and reversed() will reverse the elements in the original list object. Reversing a list is a common part of any programming language.


2 Answers

Use sorted with a custom key function and reverse=True:

print(sorted(my_list, key=lambda x: (x.endswith('log'), x), reverse=True))
#['/abc/spa/a.log',
# '/abc/spa/a.log.30.gz',
# '/abc/spa/a.log.2.gz',
# '/abc/spa/a.log.1.gz']

Based on the updated question, it seems like you are trying to sort file names. I would recommend using os.path to manipulate these strings.

First you can use os.path.splitext split out the extension to compare between .log or .gz. Then strip off the extension again to get the file number, and convert it to an integer.

For example:

import os

def get_sort_keys(filepath):
    split_file_path = os.path.splitext(filepath)
    sort_key = (split_file_path[1], *os.path.splitext(split_file_path[0]))
    return (sort_key[0], sort_key[1], int(sort_key[2].strip(".")) if sort_key[2] else 0)

print(sorted(my_list, key=get_sort_keys, reverse=True))
#['/abc/a.log',
# '/abc/a.log.30.gz',
# '/abc/a.log.29.gz',
# '/abc/a.log.14.gz',
# '/abc/a.log.12.gz',
# '/abc/a.log.10.gz',
# '/abc/a.log.8.gz',
# '/abc/a.log.6.gz',
# '/abc/a.log.5.gz',
# '/abc/a.log.4.gz',
# '/abc/a.log.3.gz',
# '/abc/a.log.2.gz',
# '/abc/a.log.1.gz']

In this version, I am not explicitly checking for endswith("log") as before, but I am relying on the fact that the log extension will sort after gz lexicographically.

like image 118
pault Avatar answered Sep 29 '22 00:09

pault


If there are multiple extension then assign rank in dictionary to have more flexibility

my_list = ['/abc/spa/a.log.1.gz',
 '/abc/spa/a.log',
 '/abc/spa/a.log.30.tar',
 '/abc/spa/a.log.30.gz',
 '/abc/spa/a.log.2.gz']

rank={'log':1,'gz':2,'tar':3}    # 'tar' is optional here
sorted(my_list,key = lambda x : (-rank.get(x.rsplit('.')[-1],0), x),reverse=True)

this will give

['/abc/spa/a.log',
 '/abc/spa/a.log.30.gz',
 '/abc/spa/a.log.2.gz',
 '/abc/spa/a.log.1.gz',
 '/abc/spa/a.log.30.tar']

For your updated question

my_list = [
     '/abc/a.log.1.gz',
     '/abc/a.log',
     '/abc/a.log.30.gz',
     '/abc/a.log.2.gz',
     '/abc/a.log.5.gz',
     '/abc/a.log.3.gz',
     '/abc/a.log.6.gz',
     '/abc/a.log.4.gz',
     '/abc/a.log.12.gz',
     '/abc/a.log.10.gz',
     '/abc/a.log.8.gz',
     '/abc/a.log.14.gz',
     '/abc/a.log.29.gz'
]
rank={'log':1,'gz':2,'tar':3}    # 'tar' is optional here
sorted(my_list,key = lambda x : (-rank.get(x.rsplit('.',1)[-1]), int(x.split('.')[-2]) if x.split('.')[-2].isdigit() else 0),reverse=True)

Output:

['/abc/a.log',
 '/abc/a.log.30.gz',
 '/abc/a.log.29.gz',
 '/abc/a.log.14.gz',
 '/abc/a.log.12.gz',
 '/abc/a.log.10.gz',
 '/abc/a.log.8.gz',
 '/abc/a.log.6.gz',
 '/abc/a.log.5.gz',
 '/abc/a.log.4.gz',
 '/abc/a.log.3.gz',
 '/abc/a.log.2.gz',
 '/abc/a.log.1.gz']
like image 31
mad_ Avatar answered Sep 29 '22 02:09

mad_