我有JSON文件(从API发布回复) - 我需要通过某个键对字典进行排序,以便按时间顺序解析JSON文件。在研究数据之后,我可以按元数据中的日期格式或通过S5CV的数字序列对其进行排序[0606] P0.xml
您可以在此处加载JSON的一个文本示例 - http://pastebin.com/0NS5BiDk
我已经编写了2个代码来按某个键对对象列表进行排序。第一个按照'文本排序。的xml。第二个是[元数据] [0] [值]。
第一个可行,但是一些XML,即使它们的数量更高,实际上也有比我预期更早的文档。
对于第二个代码,日期格式不一致,有时该值根本不存在。我正在努力以一致的方式提取日期时间格式。第二个也给了我一个错误,但我无法弄清楚为什么 - 字符串索引必须是整数。
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/pitchImageView"
android:src="@drawable/gaa_pitch"
android:scaleType="centerCrop"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/start"
android:id="@+id/stopwatchButton"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"/>
</RelativeLayout>
答案 0 :(得分:1)
显然,如果数据不可靠,你就无法使用.xml文件名对数据进行排序,因此最有希望的策略似乎就是你在第二段代码中尝试做的事情。
当我提到需要一个日期时间来将我的评论中的项目排序到您的其他问题时,我的字面意思是datetime.date
个实例,而不是像"28th july, 1933"
这样的字符串,它们无法提供正确的排序因为它们会在字典上与彼此进行比较,而不是像datetime.date
那样数字化。
这里似乎有用。它使用re
模块在通常包含它们的字符串中搜索日期模式(具有与"name"
相关联的"Comprising period from"
的日期模式)。如果字符串中有多个日期匹配,则使用最后一个。然后将其转换为date
实例,并将其作为键值返回。
由于某些项目没有有效的日期字符串,因此将默认值替换为排序目的。在下面的代码中,最早的有效日期用作默认值 - 这使得所有带日期问题的项目出现在排序列表的开头。跟随它们的任何物品都应该按照正确的顺序排列。
不确定您应该对缺少日期信息的项目做些什么 - 如果不存在,您唯一的选择是猜测一个值,忽略它们,或者认为它是错误。
# v3.2.1
import datetime
import json
import re
# default date when one isn't found
DEFAULT_DATE = datetime.date(1, 1, datetime.MINYEAR) # 01/01/0001
MONTHS = ('january february march april may june july august september october'
' november december'.split())
# dictionary to map month names to numeric values 1-12
MONTH_TO_ORDINAL = dict( zip(MONTHS, range(1, 13)) )
DMY_DATE_REGEX = (r'(3[01]|[12][0-9]|[1-9])\s*(?:st|nd|rd|th)?\s*'
+ r'(' + '|'.join(MONTHS) + ')(?:[,.])*\s*'
+ r'([0-9]{4})')
MDY_DATE_REGEX = (r'(' + '|'.join(MONTHS) + ')\s+'
+ r'(3[01]|[12][0-9]|[1-9])\s*(?:st|nd|rd|th)?,\s*'
+ r'([0-9]{4})')
DMY_DATE = re.compile(DMY_DATE_REGEX, re.IGNORECASE)
MDY_DATE = re.compile(MDY_DATE_REGEX, re.IGNORECASE)
def extract_date(item):
metadata0 = item["metadata"][0] # check only first item in metadata list
if metadata0.get("name") != "Comprising period from":
return DEFAULT_DATE
else:
value = metadata0.get("value", "")
matches = DMY_DATE.findall(value) # try dmy pattern (most common)
if matches:
day, month, year = matches[-1] # use last match if more than one
else:
matches = MDY_DATE.findall(value) # try mdy pattern...
if matches:
month, day, year = matches[-1] # use last match if more than one
else:
print('warning: date patterns not found in "{}"'.format(value))
return DEFAULT_DATE
# convert strings found into numerical values
year, month, day = int(year), MONTH_TO_ORDINAL[month.lower()], int(day)
return datetime.date(year, month, day)
# test files: 'json_sample.txt', 'india_congress.txt', 'olympic_games.txt'
with open('json_sample.txt', 'r') as f:
j = json.load(f)
orig_list = j["tree"]["children"][0]["children"]
sorted_list = sorted(orig_list, key=extract_date)
for item in sorted_list:
print(json.dumps(item, indent=4))
要回答您最新的后续问题,您可以使用extract_date()
预先在generator expression中将某些内容过滤掉,从而将列表中没有可识别日期的所有项目遗漏掉像这样:
# to obtain a list containing only entries with a parsable date
cleaned_list = sorted((x for x in orig_list if extract_date(x) != DEFAULT_DATE),
key=extract_date)
如果您的项目的排序列表都具有有效日期,您可以执行以下操作,再次重复使用extract_date()
函数:
# extract and display dates of items in cleaned list
print('first date: {}'.format(extract_date(cleaned_list[0])))
print('middle date: {}'.format(extract_date(cleaned_list[len(cleaned_list)//2])))
print('last date: {}'.format(extract_date(cleaned_list[-1])))
多次在同一个项目上调用extract_date()
效率有点低。为了避免这种情况,您可以轻松地添加它即时返回到对象的datetime.date
值,因为它是一个字典,然后只需要经常引用它,只需要很少的额外开销:
# add extracted datetime.date entry to a list item[i] if a valid one was found
date = extract_date(some_list[i])
if date != DEFAULT_DATE: # valid date found?
some_list[i]['date'] = date # save by adding it to object
通过将提取日期存储在项目本身中,可以有效地缓存提取日期。之后,datetime.date
值可以简单地用some_list[i]['date']
引用。
作为一个具体的例子,考虑这个修改的例子,显示第一个,中间和最后一个对象的日期:
# display dates of items in cleaned list
print('first date: {}'.format(cleaned_list[0]['date']))
middle = len(cleaned_list)//2
print('middle date: {}'.format(cleaned_list[middle]['date']))
print('last date: {}'.format(cleaned_list[-1]['date']))