I have a problem. I have list of lists that look something like this:
[
[datetime.date(2019, 3, 29), Decimal('44819.75')],
[datetime.date(2019, 3, 29), Decimal('45000.00')],
[datetime.date(2019, 3, 28), Decimal('0.00')],
[datetime.date(2019, 3, 22), Decimal('-275.00')],
[datetime.date(2019, 3, 22), Decimal('-350.00')],
[datetime.date(2019, 3, 22), Decimal('-175.00')]
]
I need sorting to be on date field(1st one), but each set of same dates must be sorted in reverse order. Resulting list must look like this:
[
[datetime.date(2019, 3, 29), Decimal('45000.00')],
[datetime.date(2019, 3, 29), Decimal('44819.75')],
[datetime.date(2019, 3, 28), Decimal('0.00')],
[datetime.date(2019, 3, 22), Decimal('-175.00')],
[datetime.date(2019, 3, 22), Decimal('-350.00')],
[datetime.date(2019, 3, 22), Decimal('-275.00')],
]
As you can see list is ordered by date but, for the same dates list is reversed.
dates are still descending 2019-3-29 2019-3-28 2019-3-22 but for each date, if there more than 1 element for that date, items are reversed.
for 2019-3-29 there are 2 element
[datetime.date(2019, 3, 29), Decimal('44819.75')],
[datetime.date(2019, 3, 29), Decimal('45000.00')],
and in resulting list of lists order is reversed
[datetime.date(2019, 3, 29), Decimal('45000.00')],
[datetime.date(2019, 3, 29), Decimal('44819.75')],
Unfortunately i can not find most pythonic way to do that, only ugly nested cycles
I took the liberty to simplify the datatypes since it is easier to read this way.
# Simplified representation.
# a few random values at the start and then multiple 2's and that the current order is a,b,c
# We expect all values to be sorted on the integer part first. And that the order for the 2's is c,b,a at the end.
data = [
[1, '-'],
[5, '-'],
[3, '-'],
[2, 'a'],
[2, 'b'],
[2, 'c']
]
data = data[::-1]
data = sorted(data, key=lambda x:x[0])
Printing the data will yield:
[1, '-']
[2, 'c']
[2, 'b']
[2, 'a']
[3, '-']
[5, '-']
Which I believe is that you wanted.
This solution is very easy to read which has its benefits when working with others.
sorted
in python is a stable sorting algorithm. This is why you if you sort normally the order of 'a b c' is preserved. Thats why reversing first works, sorted will not change the order in which equal items appeared.
Note that this also works.
data = sorted(data, key=lambda x:x[0], reverse=True)
data = data[::-1]
Here we do a reverse sort and then read the data backwards.
An O(n) solution using itertools.groupby
to group and reverse each date's items:
data = [d for _, g in groupby(data, lambda d: d[0]) for d in [*g][::-1]]
(This requires the dates to already be descending in the input, but your question, especially your "dates are still descending" sounds like that's indeed the case.)
Demo:
import datetime
from decimal import Decimal
from itertools import groupby
data = [
[datetime.date(2019, 3, 29), Decimal('44819.75')],
[datetime.date(2019, 3, 29), Decimal('45000.00')],
[datetime.date(2019, 3, 28), Decimal('0.00')],
[datetime.date(2019, 3, 22), Decimal('-275.00')],
[datetime.date(2019, 3, 22), Decimal('-350.00')],
[datetime.date(2019, 3, 22), Decimal('-175.00')]
]
data = [d for _, g in groupby(data, lambda d: d[0]) for d in [*g][::-1]]
for d in data:
print(d)
Output:
[datetime.date(2019, 3, 29), Decimal('45000.00')]
[datetime.date(2019, 3, 29), Decimal('44819.75')]
[datetime.date(2019, 3, 28), Decimal('0.00')]
[datetime.date(2019, 3, 22), Decimal('-175.00')]
[datetime.date(2019, 3, 22), Decimal('-350.00')]
[datetime.date(2019, 3, 22), Decimal('-275.00')]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With