首页 > 解决方案 > Python3减少函数

问题描述

我在具有重复项的 JS 中使用了以下 dict/JSON:

{
  0:{
    "id" : 1,
    "name": "test"
  },
  1:{
    "id" : 2,
    "name": "other name"
  },
  2:{
    "id" : 1,
    "name": "does not have to be the same name"
  },{
    "id" : 3,
    "name": "but they could be the same"
  },
  3:{
    "id" : 2,
    "name": "other name"
  }
}

我想把它减少到:

{
  0:{
    "id" : 1,
    "name": "test"
  },
  1:{
    "id" : 2,
    "name": "other name"
  },
  2:{
    "id" : 3,
    "name": "but they could be the same"
  }
}

标准是 id 必须是唯一的,无论项目的其余部分是否不同。

对于 JS,我使用了以下代码:

const data = [ { "id" : 1, "name": "test" }, { "id" : 2, "name": "other name" }, { "id" : 1, "name": "does not have to be the same name" },{ "id" : 3, "name": "but they could be the same" },{ "id" : 2, "name": "other name" }, ],
      unique = Object.values(data.reduce((r, o) => {
        r[o.id] = r[o.id] || o;
        return r;
      },{}));
console.log(unique);

但是,我似乎无法对 python3.9 做同样的事情。我找到了该functools.reduce()函数并尝试将其与 lambas 一起使用,但 dics 与 JSON 对象不同。

标签: pythonpython-3.x

解决方案


请注意,您提供的输入是无效的 JSON。根据你的JS,结构应该是这样的。

foo = [
    {
        "id" : 1,
        "name": "test"
    },
    {
        "id" : 2,
        "name": "other name"
    },
    {
        "id" : 1,
        "name": "does not have to be the same name"
    },
    {
         "id" : 3,
         "name": "but they could be the same"
    },
    {
         "id" : 2,
         "name": "other name"
    }
]

话虽这么说,如果你想要一个使用 的解决方案reduce,这样的东西会起作用。

from functools import reduce
foo = [
    {
        "id" : 1,
        "name": "test"
    },
    {
        "id" : 2,
        "name": "other name"
    },
    {
        "id" : 1,
        "name": "does not have to be the same name"
    },
    {
         "id" : 3,
         "name": "but they could be the same"
    },
    {
         "id" : 2,
         "name": "other name"
    }
]
# in my opinion, the readability suffers here
# sometimes you need to be ok with using more than one line
result = reduce(lambda x, y: x + [y] if not any(i['id'] == y['id'] for i in x) else x, foo, [])
print(result)

一个更易读的例子是使用实际函数而不是lambda.

from functools import reduce
foo = [
    {
        "id" : 1,
        "name": "test"
    },
    {
        "id" : 2,
        "name": "other name"
    },
    {
        "id" : 1,
        "name": "does not have to be the same name"
    },
    {
         "id" : 3,
         "name": "but they could be the same"
    },
    {
         "id" : 2,
         "name": "other name"
    }
]
def build_list(result_list, list_element):
    if not any(list_element['id'] == i['id'] for i in result_list):
        return result_list + [list_element]
    return result_list

result = reduce(build_list, foo, [])
print(result)

但这仍然不是我写它的风格。就我个人而言,我会用 a 跟踪重复项set并完全避免理解 / reduce

foo = [
    {
        "id" : 1,
        "name": "test"
    },
    {
        "id" : 2,
        "name": "other name"
    },
    {
        "id" : 1,
        "name": "does not have to be the same name"
    },
    {
         "id" : 3,
         "name": "but they could be the same"
    },
    {
         "id" : 2,
         "name": "other name"
    }
]
result = []
ids = set()
for dct in foo:
    if not dct['id'] in ids:
        ids.add(dct['id'])
        result.append(dct)
print(result)

推荐阅读