web-dev-qa-db-fra.com

python trie la liste de json par valeur

J'ai un fichier composé de JSON, chacun une ligne, et je veux trier le fichier par update_time inversé.

exemple de fichier JSON:

{ "page": { "url": "url1", "update_time": "1415387875"}, "other_key": {} }
{ "page": { "url": "url2", "update_time": "1415381963"}, "other_key": {} }
{ "page": { "url": "url3", "update_time": "1415384938"}, "other_key": {} }

veulent une sortie:

{ "page": { "url": "url1", "update_time": "1415387875"}, "other_key": {} }
{ "page": { "url": "url3", "update_time": "1415384938"}, "other_key": {} }
{ "page": { "url": "url2", "update_time": "1415381963"}, "other_key": {} }

mon code:

#!/bin/env python
#coding: utf8

import sys
import os
import json
import operator

#load json from file
lines = []
while True:
    line = sys.stdin.readline()
    if not line: break
    line = line.strip()
    json_obj = json.loads(line)
    lines.append(json_obj)

#sort json
lines = sorted(lines, key=lambda k: k['page']['update_time'], reverse=True)

#output result
for line in lines:
    print line

Le code fonctionne correctement avec un exemple de fichier JSON, mais si un JSON n'a pas de 'update_time', il déclenchera une exception KeyError. Existe-t-il des moyens sans exception de procéder?

24
icycandy

Écrivez une fonction qui utilise try...except pour gérer le KeyError, puis utilisez-le comme argument key au lieu de votre lambda.

def extract_time(json):
    try:
        # Also convert to int since update_time will be string.  When comparing
        # strings, "10" is smaller than "2".
        return int(json['page']['update_time'])
    except KeyError:
        return 0

# lines.sort() is more efficient than lines = lines.sorted()
lines.sort(key=extract_time, reverse=True)
22
Ferdinand Beyer

Vous pouvez utiliser dict.get() avec une valeur par défaut:

lines = sorted(lines, key=lambda k: k['page'].get('update_time', 0), reverse=True)

Exemple:

>>> lines = [
...     {"page": {"url": "url1", "update_time": "1415387875"}, "other_key": {}},
...     {"page": {"url": "url2", "update_time": "1415381963"}, "other_key": {}},
...     {"page": {"url": "url3", "update_time": "1415384938"}, "other_key": {}},
...     {"page": {"url": "url4"}, "other_key": {}},
...     {"page": {"url": "url5"}, "other_key": {}}
... ]
>>> lines = sorted(lines, key=lambda k: k['page'].get('update_time', 0), reverse=True)
>>> for line in lines:
...     print line
... 
{'other_key': {}, 'page': {'url': 'url1', 'update_time': '1415387875'}}
{'other_key': {}, 'page': {'url': 'url3', 'update_time': '1415384938'}}
{'other_key': {}, 'page': {'url': 'url2', 'update_time': '1415381963'}}
{'other_key': {}, 'page': {'url': 'url4'}}
{'other_key': {}, 'page': {'url': 'url5'}}

Cependant, je suivrais toujours le principe EAFP que Ferdinand a suggéré - de cette façon, vous géreriez également les cas où la clé page est également manquante. Il est beaucoup plus facile de le laisser échouer et de le gérer que de vérifier toutes sortes de cas d'angle.

14
alecxe
# sort json
lines = sorted(lines, key=lambda k: k['page'].get('update_time', 0), reverse=True)
8
gurel_kaynak