如果存在其ID号,则删除对象

时间:2019-07-15 14:26:36

标签: python

我有一个Python文件,该文件格式化JSON数组(10000个)中的多个对象。完成此操作后,我将所有内容转储到新的JSON文件中。 Bu我想基于id编写仅包含50个对象的文件。完成此操作后,我将在演示文件中写入对象。

with open('./output/' + datefile + 'complete_format-test.json', 'w', encoding='utf-8') as json_output:
  json.dump(data, json_output, indent=4, ensure_ascii=False)

  for i in data:
        demoID= {[10202, 10300, 10615, 10890, 11161, 11204, 11460, 12043, 12054, 12617, 12633, 12736, 13689, 13730, 13755, 13764, 13894, 14472, 14837, 15328, 15383, 15403, 15449, 15771,
                 16121, 16134, 16205, 16242, 16434, 16485, 16487, 16622, 17769, 18001, 18074, 18673, 18689, 18762, 18863, 18912, 19243, 19478, 19758, 19895, 20299, 20981, 21010, 21064, 21078]}

        if not demoID in i["objectID"]:
            del(i)
            print(i)

JSON示例:

  [{
    "objectID": 21064,
    "cars_getroute": "volkswagen-typ",
  },
  {
    "objectID": 21078,
    "cars_getroute": "volvo-123",
  } ...
]

因此,如果objectID在demoID列表中,则保留它并删除其他对象。 目前,我有一个TypeError: unhashable type: 'list'

2 个答案:

答案 0 :(得分:2)

您应将demoID定义为set,而内部不包含[]

然后您可以像这样过滤出正确的数据:

data = [
    {
        "objectID": 21064,
        "cars_getroute": "volkswagen-typ",
    },
    {
        "objectID": 999,
        "cars_getroute": "999",
    },
    {
        "objectID": 21078,
        "cars_getroute": "volvo-123",
    },
]

demoID = {
    10202, 10300, 10615, 10890, 11161, 11204, 11460, 12043, 12054, 12617, 12633, 12736, 13689, 13730, 13755, 13764,
    13894, 14472, 14837, 15328, 15383, 15403, 15449, 15771,
    16121, 16134, 16205, 16242, 16434, 16485, 16487, 16622, 17769, 18001, 18074, 18673, 18689, 18762, 18863, 18912,
    19243, 19478, 19758, 19895, 20299, 20981, 21010, 21064, 21078}

data = [d for d in data if d["objectID"] in demoID]

print(data)

答案 1 :(得分:2)

您观察到的错误与您定义demoID的方式有关。 基本上:

x = {[1, 2, 3]}

尝试生成一个set(),该元素的唯一元素是列表[1, 2, 3]。 但是,不可能将list用作集合的元素,因为它们不是可散列的。这基本上就是那个错误告诉你的。

但是,您的代码还有许多其他缺点:

  1. demoID是在循环内定义的,没有特别充分的理由,每次都会被浪费地重新计算;
  2. 您尝试在data(使用del)进行循环修改时对其进行修改。这可能会导致您的容器出现不一致的行为,应避免使用该容器;
  3. 删除后,您尝试使用i(与print一起使用)
  4. 循环not demoID in i["objectID"]的条件是不自然的,并且不太可能执行您想做的事情:demoID是一个容器,而i["objectID"]是一个元素,它们应该颠倒过来,例如i["objectID"] in demoID;
  5. 您说您想将您的结果限制为大约50个条目,但这在代码的任何地方都没有实施。也许这是基于这样一个假设,即您的"objectID"是唯一的,并且demoID的长度是50,但是您可能想更明确地做到这一点。

鉴于此,而且我无权访问您的数据,我将编写一些代码来处理一些没有这些缺点并且应该容易适用于您的情况的测试数据:

import random
import string

random.seed(0)

# generate dummy data
num = 10000
source_data = [
    {'objectID': random.randint(1, num),
     'cars_getroute': string.ascii_letters[0:random.randint(1, 50)]}
    for _ in range(num)]

print(len(source_data))
# 10000

现在假设您要限制( filter source_data仅包含objectID中指定的demoID。标准方法是生成仅包含 filtered 元素的新容器:

# generate dummy `demoID`
# here we are using a `set()` which is a sensible choice, given the expected usage,
# but we could have used e.g. a list or a tuple
demoID = {random.randint(1, num) for _ in range(50)}

# filter-out `source_data`
data = [
    elem
    for elem in source_data
    if elem['objectID'] in demoID]

# output could be different depending on the random seed
# in general, it is not `50` due to possible duplicates
# in both `demoID` and `source_data['objectID']`
print(len(data))
# 51

如果您现在要主动限制最大数量为50的数字,则应切片您的数据,即:

max_num = 50
demo_data = data[:max_num]

# could be less if `data` has less than `max_num` items
print(len(data[:max_num]))
# 50

(编辑:请注意,@ Adam.Er8的答案使用此处提出的相同方法)


编辑2

如果您确实要修改source_data,通常的方法是在第一个循环中获取要删除的列表元素的索引,然后在第二个循环中将其删除(将索引从大到大排序)。较小,因此在删除项目时不会使先前计算的索引值无效),例如

# note that the condition here is the negation of
# what is used with the *filter* approach
to_remove = [
     i
     for i, elem in enumerate(source_data)
     if not elem['objectID'] in demoID]

for i in sorted(to_remove, reverse=True):
    source_data.pop(i)

print(len(source_data))
# 51