在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(开始计算添加新属性的时间)?
我欢迎任何想法。
答案 0 :(得分:2)
JSON.parse
reviver和JSON.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 {}