Home > Back-end >  How to sort JSON file by value
How to sort JSON file by value

Time:08-25

I have a big JSON file that contains timezones like the following:

{
   "timezones":[
      {
         "id":1,
         "name":"(UTC) Coordinated Universal Time",
         "utc_offset":" 0"
      },
      {
         "id":2,
         "name":"(UTC 8:45) Australian Central Standard Time",
         "utc_offset":" 8:45"
      },
      {
         "id":3,
         "name":"(UTC-5) Acre Time",
         "utc_offset":"-5"
      },
      {
         "id":4,
         "name":"(UTC 8:45) Australian Central Western Standard Time",
         "utc_offset":" 8:45"
      }
   ]
}

I'm trying to sort it according to the utc_offset values from - to , if the utc_offset are identical, then by name alphabetically. So The wanted result should be like this:

{
   "timezones":[
      {
         "id":3,
         "name":"(UTC-5) Acre Time",
         "utc_offset":"-5"
      },
      {
         "id":1,
         "name":"(UTC) Coordinated Universal Time",
         "utc_offset":" 0"
      },
      {
         "id":2,
         "name":"(UTC 8:45) Australian Central Standard Time",
         "utc_offset":" 8:45"
      },
      {
         "id":4,
         "name":"(UTC 8:45) Australian Central Western Standard Time",
         "utc_offset":" 8:45"
      }
   ]
}

Using the following code I tried:

lines = lines.sort(int(json['timezones']['utc_offset']), reverse=True)

print(lines)

But it's showing an error AttributeError: 'dict' object has no attribute 'sort'

How I may do this?

CodePudding user response:

Maybe something like this using regexps for parsing utc_offset:

adict = {
    "timezones": [
        {
            "id": 1,
            "name": "(UTC) Coordinated Universal Time",
            "utc_offset": " 0"
        },
        {
            "id": 2,
            "name": "(UTC 8:45) Australian Central Standard Time",
            "utc_offset": " 8:45"
        },
        {
            "id": 3,
            "name": "(UTC-5) Acre Time",
            "utc_offset": "-5"
        },
        {
            "id": 4,
            "name": "(UTC 8:45) Australian Central Western Standard Time",
            "utc_offset": " 8:45"
        }
    ]
}

timezones = adict['timezones']

pattern = re.compile(r'^(?P<sign>[ -])(?P<hour>\d ):?(?P<minutes>\d )?')


def get_time(string):
    m = pattern.match(string)
    if not m:
        return False
    sign, hour, minutes = m.groupdict().values()
    result = int(hour) * 60   (int(minutes) if minutes else 0)
    result = -result if sign == '-' else result
    return result


print(sorted(timezones, key=lambda x: (get_time(x['utc_offset']), x['name'])))

Output:

[
    {'id': 3, 'name': '(UTC-5) Acre Time', 'utc_offset': '-5'},
    {'id': 1, 'name': '(UTC) Coordinated Universal Time', 'utc_offset': ' 0'},
    {'id': 2, 'name': '(UTC 8:45) Australian Central Standard Time', 'utc_offset': ' 8:45'},
    {'id': 4, 'name': '(UTC 8:45) Australian Central Western Standard Time', 'utc_offset': ' 8:45'}
]

CodePudding user response:

json = {
   "timezones":[
      {
         "id":1,
         "name":"(UTC) Coordinated Universal Time",
         "utc_offset":" 0"
      },
      {
         "id":2,
         "name":"(UTC 8:45) Australian Central Standard Time",
         "utc_offset":" 8:45"
      },
      {
         "id":3,
         "name":"(UTC-5) Acre Time",
         "utc_offset":"-5"
      },
      {
         "id":4,
         "name":"(UTC 8:45) Australian Central Western Standard Time",
         "utc_offset":" 8:45"
      }
   ]
}

def to_mins(e):
    offset = e['utc_offset']
    sign = 1 if offset[0] == ' ' else -1
    hm = offset[1:].split(':')
    h, m = (hm[0], 0) if len(hm) == 1 else hm
    return sign * (60 * int(h)   int(m))



print(sorted(json['timezones'], key=to_mins))

prints

[{'id': 3, 'name': '(UTC-5) Acre Time', 'utc_offset': '-5'},
 {'id': 1, 'name': '(UTC) Coordinated Universal Time', 'utc_offset': ' 0'},
 {'id': 2,
  'name': '(UTC 8:45) Australian Central Standard Time',
  'utc_offset': ' 8:45'},
 {'id': 4,
  'name': '(UTC 8:45) Australian Central Western Standard Time',
  'utc_offset': ' 8:45'}]

CodePudding user response:

So first we transform the timezone strings into numeric values, then sort using the sorted function. If you want to get the results in descending order, you can change the value of the boolean parameter reverse.

def get_minutes_tz(str_tz):
    min_tz = None
    # add more checks on the format of the timezone string (you can also use regex)
    if len(str_tz)>0 and isinstance(str_tz, str) and (str_tz.startswith(' ')  or str_tz.startswith('-')):
        splits = str_tz[1:].split(':')
        min_tz = int(str_tz[0]   str(int(splits[0])*60 if len(splits)>0 else 0   int(splits[1] if len(splits)>1 else 0)))
    return min_tz

sorted(d['timezones'], key=lambda k: get_minutes_tz(k['utc_offset']), 
       reverse=False)

result:

[{'id': 3, 'name': '(UTC-5) Acre Time', 'utc_offset': '-5'},
 {'id': 1, 'name': '(UTC) Coordinated Universal Time', 'utc_offset': ' 0'},
 {'id': 2,
  'name': '(UTC 8:45) Australian Central Standard Time',
  'utc_offset': ' 8:45'},
 {'id': 4,
  'name': '(UTC 8:45) Australian Central Western Standard Time',
  'utc_offset': ' 8:45'}]
  • Related