给定对象数组,计算定义了多少个(可能不同)属性

时间:2019-11-29 23:55:39

标签: javascript arrays set counting

在GeoJSON文件中,某些属性由整个集合(数组)的所有“功能”(元素)共享。但是某些属性仅针对集合的子集定义。 我发现了这个问题:[javascript] counting properties of the objects in an array of objects,但不能解决我的问题。

示例:

const features =
[ {"properties":{"name":"city1","zip":1234}, "geometry":{"type":"polygon","coordinates":[[1,2],[3,4] ...]}},
  {"properties":{"name":"city2","zip":1234}, "geometry":{"type":"polygon","coordinates":[[1,2],[3,4] ...]}},
  {"properties":{"name":"city3"},"geometry":{"type":"multiPolygon","coordinates":[[[1,2],[3,4] ...]]}},
// ... for instance 1000 different cities
  {"properties":{"name":"city1000","zip":1234,"updated":"May-2018"}, "geometry":{"type":"polygon","coordinates":[...]}}
];

预期结果:列出所有现有属性及其基数的信息,让我们知道数据集的完成情况。例如:

properties: 1000, properties.name: 1000, properties.zip: 890, properties.updated: 412,
geometry: 1000, geometry.type: 1000, geometry.coordinates: 1000

我有一个(相当复杂的)解决方案,但我确实怀疑有些人已经遇到了同样的问题(似乎是数据科学的经典之作),而其中的一个更好的(性能很重要)。

这是我笨拙的解决方案:

// 1: list all properties encountered in the features array, at least two levels deep
const countProps = af => af.reduce((pf,f) =>
                                            Array.from(new Set(pf.concat(Object.keys(f)))), []);
// adding all the properties of each individual feature, then removing duplicates using the array-set-array trick
const countProp2s = af => af.reduce((pf,f) =>
                                            Array.from(new Set(pf.concat(Object.keys(f.properties)))), []);
const countProp2g = af => af.reduce((pf,f) =>
                                            Array.from(new Set(pf.concat(Object.keys(f.geometry)))), []);

// 2: counting the number of defined occurrences of each property of the list 1
const countPerProp =  (ff) => pf => ` ${pf}:${ff.reduce((p,f)=> p+(!!f[pf]), 0)}`;
const countPerProp2s = (ff) => pf => ` ${pf}:${ff.reduce((p,f)=> p+(!!f.properties[pf]), 0)}`;
const countPerProp2g = (ff) => pf => ` ${pf}:${ff.reduce((p,f)=> p+(!!f.geometry[pf]), 0)}`;
const cardinalities = countProps(features).map((kk,i) => countPerProp(ff)(kk)) +
                      countProp2s(features).map(kk => countPerProp2s(ff)(kk)) +
                      countProp2g(features).map(kk => countPerProp2g(ff)(kk));

因此,存在三个问题:

-步骤1:对于一个相当简单的操作,这是很多工作(在删除大部分内容之前添加所有内容)。而且,这不是递归的,第二级是“手动强制”的。

步骤2,递归解决方案可能是更好的解决方案。

-是否可以在单个步骤中执行步骤1和2(开始计算添加新属性的时间)?

我欢迎任何想法。

3 个答案:

答案 0 :(得分:2)

JSON.parse reviverJSON.stringify replacer可用于检查所有键值对:

var counts = {}, json = `[{"properties":{"name":"city1","zip":1234}, "geometry":{"type":"polygon","coordinates":[[1,2],[3,4]]}},{"properties":{"name":"city2","zip":1234}, "geometry":{"type":"polygon","coordinates":[[1,2],[3,4]]}},{"properties":{"name":"city3"},"geometry":{"type":"multiPolygon","coordinates":[[[1,2],[3,4]]]}},{"properties":{"name":"city1000","zip":1234,"updated":"May-2018"}, "geometry":{"type":"polygon","coordinates":[]}} ]`

var features = JSON.parse(json, (k, v) => (isNaN(k) && (counts[k] = counts[k] + 1 || 1), v))

console.log( counts, features )

答案 1 :(得分:1)

考虑尝试以下方法。它只是一个减少,在forEach的内部有几个嵌套。它检查用于指示计数的键是否存在于要返回的对象中,如果不存在,则将其初始化为0。然后,无论这些键是否存在,其对应值都将递增1。

Repl在这里:https://repl.it/@dexygen/countobjpropoccur2levels,下面的代码:

const features =
[ {"properties":{"name":"city1","zip":1234}, "geometry":{"type":"polygon","coordinates":[[1,2],[3,4]]}},
  {"properties":{"name":"city2","zip":1234}, "geometry":{"type":"polygon","coordinates":[[1,2],[3,4]]}},
  {"properties":{"name":"city3"},"geometry":{"type":"multiPolygon","coordinates":[[[1,2],[3,4]]]}},
  {"properties":{"name":"city1000","zip":1234,"updated":"May-2018"}, "geometry":{"type":"polygon","coordinates":[]}}
];

const featuresCount = features.reduce((count, feature) => {
  Object.keys(feature).forEach(key => {
    count[key] = count[key] || 0;
    count[key] += 1;
    Object.keys(feature[key]).forEach(key2 => {
      let count2key = `${key}.${key2}`;
      count[count2key] = count[count2key] || 0;
      count[count2key] += 1;
    });
  });
  return count;
}, {});

console.log(featuresCount);

/*
{ properties: 4,
  'properties.name': 4,
  'properties.zip': 3,
  geometry: 4,
  'geometry.type': 4,
  'geometry.coordinates': 4,
  'properties.updated': 1 }
*/

答案 2 :(得分:-1)

使用杰克逊使用JSON的多态序列化。如下所示。您的基本界面将具有所有通用属性,并为每个变体创建子类型。依靠每种类型都会满足您的需求

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,include = JsonTypeInfo.As.PROPERTY,property =“ name”)@JsonSubTypes({@ JsonSubTypes.Type(value = Lion.class,name =“ lion”), @ JsonSubTypes.Type(value = Tiger.class,name =“ tiger”),})公共接口Animal {}