首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ijson kvitems意外行为

ijson kvitems意外行为
EN

Stack Overflow用户
提问于 2021-10-27 11:53:24
回答 1查看 237关注 0票数 1

我使用ijson来解析大型JSON。我有这段代码,它应该给出对应于相关JSON字段的值的dict

代码语言:javascript
复制
def parse_kvitems(kv_gen, key_list):
    results = {}
    for key in key_list:
        results[key] = (v for k, v in kv_gen if k == key)
    return results

with zipfile.ZipFile(fr'{directory}\{file}', 'r') as zipObj:
    # Get a list of all archived file names from the zip
    listOfFileNames = zipObj.namelist()
    # Iterate over the file names
    for fileName in listOfFileNames:
        # Check filename endswith csv.  dont extract, ijson wants bytes input and json.loads can run into memory issues with smash jsons.No documentation available 
        if fileName.endswith('.json'):
            # Extract a single file from zip
            with zipObj.open(fileName) as f:

                #HERE:
                records = ijson.kvitems(f, 'records.item')
                data_list = ['id', 'features', 'modules', 'dbxrefs', 'description']    
                parsed_records = parse_kvitems(records, data_list) --> give me a dict of dict values that fall under the json headings in data_list

我认为keys对象的作用就像一个生成器,并且只通过一次运行(我得到了'id'的期望值,但是parsed_records中的其他data_list键是空的)。

为了解决这个问题,我试着列出一个重复的kv_gen的列表:

代码语言:javascript
复制
def parse_kvitems(kv_gen, key_list):
    kv_list = [kv_gen] * len(key_list) #this bit
    results = {}
    for key, kv_gen in zip(key_list, kv_list):
        results[key] = (v for k, v in kv_gen if k == key)
    return results

这也给了我同样的错误。我认为易变可能是这里的罪魁祸首,但我不能在kvitems对象上使用kvitems来查看它是否修复了。

然后我尝试使用itertools.cycle(),但这似乎是以一种我不明白的方式起作用的:

代码语言:javascript
复制
def parse_kvitems(kv_gen, key_list):
    infinite_kvitems = itertools.cycle(kv_gen)
    results = {}
    for key in key_list:
        results[key] = (v for k, v in infinite_kvitems if k == key)
    return results

另外,下面的内容也很有效(从这个意义上讲,它提供了与我使用json.load()加载JSON时所看到的值相匹配的值):

代码语言:javascript
复制
records = ijson.kvitems(f, 'records.item')
ids = (v for k, v in records if k == 'id')
features = (v for k, v in records if k == 'features')
modules = (v for k, v in records if k == 'modules')

我只想知道为什么我的函数没有,特别是当记录对象在上面多次运行时.

编辑罗德里戈

,但是,您并没有显示您如何发现最终的字典中有id的值,而不是其他键的值。我假设这仅仅是因为您首先要迭代解析_records‘’id‘值下的值。当您这样做时,生成器表达式就会被计算出来,底层的kvitems生成器就会耗尽。

是的,这是正确的--我正在将每个val转换成一个列表,以检查每个键都有一个包含相同数量的项目的生成器,因为我担心如果下游zip操作有比最小生成器更多的对象,它们可能会截断一些值。

我没有转换成函数中的列表,因为我认为生成器将是一个更好的返回对象(较少的内存密集型等),然后我可以将其转换为函数外部所需的列表。

,您说您的最后一段代码按照预期工作。这是唯一让我感到惊讶的地方,特别是当您在创建生成器表达式之后真正、真正地检查(即评估)所有三个生成器表达式时。如果您能够澄清是否是这种情况,这将是有趣的;否则,如果您创建了所有三个生成器表达式,但随后评估一个或另一个,那么这里没有意外(因为“关于结果集合”的解释)。

基本上,它给了我希望的值,当我以一个压缩的生成器集合的形式运行这些项时,并将这些项附加到列表中。但是这可能需要更多的调查,JSON非常复杂,所以我可能遗漏了一些东西。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-10-27 13:02:30

关于结果收集

注意如何从kvitems中收集结果。在上面的所有例子中,您使用的是生成器表达式,它们本身就是惰性评估的,这可能会导致误解。然而,您并没有显示您如何发现最终的字典中有id的值,而没有其他键的值。我假设这只是因为您首先要迭代parse_records['id']值下的值。当您这样做时,生成器表达式就会被计算出来,底层的kvitems生成器就会耗尽。当您迭代其他生成器表达式的值时,提供给它们的底层kvitems生成器就会耗尽,因此不会产生任何结果。但是,如果要首先遍历另一个键的值,则应该看到该键的值,而不是其他键的值。

生成器表达式本身是很棒的,但在这种情况下,它可能会增加混乱。如果您想避免这种情况,您可能希望将这些序列合并为列表(例如,使用[... for k, v in kvitems ...]而不是(... for k, v in kvitems ...))。

关于kvitems

正如您所指出的,kvitems是一个单程生成器(或者在输入类似异步文件的对象时是一个单程异步生成器),因此,一旦您对它进行了充分的迭代,进一步的迭代就不会产生任何值。这就是为什么在您的原始代码中确实获得了id的值,而不是在对已经迭代的kvitems对象的后续迭代中收集的其他键的值。

试图复制kvitems对象也是假的:正如您还发现的那样,您只是在所有位置创建一个具有相同对象的列表,而不是原始对象的副本。

尝试copy kvitems是完全不可能的。获得N个“副本”的唯一选项是实际构造N个不同的对象;然而,这意味着输入文件将被读取N次(并且需要打开N次,因为kvitems将推进给定的文件,直到它没有任何更多的输入)。有可能,但不是很好。

itertools.cycle的结果是一个无限生成器。然后使用它作为基础来构造不同的生成器表达式(所以,懒散计算)。你提到这个解决方案是以“你不明白”的方式起作用的,但不要钻研到底发生了什么。我的期望是,当试图检查任何键的值时,您会遇到一个无限循环,因为您的生成器表达式正在无限生成器上迭代,或者类似的东西。

您说您的最后一段代码按照预期工作。这是唯一让我感到惊讶的地方,特别是当您在创建生成器表达式之后真正、真正地检查(即评估)所有三个生成器表达式时。如果您能够澄清是否是这种情况,这将是有趣的;否则,如果您创建了所有三个生成器表达式,但随后评估一个或另一个,那么这里没有意外(因为“关于结果集合”的解释)。

如何解决你的问题

基本上,所有这些都归结为在kvitems上执行一次迭代。例如,您可以尝试这样的方法:

代码语言:javascript
复制
def parse_kvitems(kvitems, keys):
    results = collections.defaultdict(list)
    for k, v in kvitems:
        if k in keys:
            results[k].append(v)
    return results

我想应该可以的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69738173

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档