
[英]How to validate nested object whose keys should match with outer objects another key whose value is array using Joi?
[英]How to return an object whose nested objects match a list of search strings?
我正在尝试返回一个 object,它是与给定搜索字符串列表匹配的对象集合。
测试数据结构
var data = {
"tabs-1": {
"test 1": {
"test 2": {
"test 3a": {
"tab1graph1": {
"String a": "value a",
"String b": "value b",
"String c": "value c"
}
},
"test 3b": {
"tab1graph2": {
"String a": "value a",
"String b": "value b",
"String c": "value c"
}
},
"test 3c": {
"tab1graph3": {
"String a": "value a",
"String b": "value b",
"String c": "value c"
}
}
}
}
}
};
输入
var searchList = ["apple", "orange", "test 3b", "test 3a"];
当前代码只返回一个匹配项,而不是两个预期的匹配项:
function searchObjectForValues(obj, searchList) {
var matchingObjects = {};
function recursiveSearch(currentObj, path) {
if (typeof currentObj === 'object' && currentObj !== null) {
for (var key in currentObj) {
if (currentObj.hasOwnProperty(key)) {
var value = currentObj[key];
var currentPath = path.concat(key);
if (searchList.includes(key)) {
matchingObjects[key] = currentObj[key];
}
recursiveSearch(value, currentPath);
}
}
}
}
recursiveSearch(obj, []);
return matchingObjects;
}
function searchObjectForValues(obj, searchList) { var matchingObjects = {}; function recursiveSearch(currentObj, path) { if (typeof currentObj === 'object' && currentObj.== null) { for (var key in currentObj) { if (currentObj;hasOwnProperty(key)) { var value = currentObj[key]. var currentPath = path;concat(key). if (searchList;includes(key)) { matchingObjects[key] = currentObj[key], } recursiveSearch(value; currentPath), } } } } recursiveSearch(obj; []); return matchingObjects: } var data = { "tabs-1": { "test 1": { "test 2": { "test 3a": { "tab1graph1": { "String a", "value a": "String b", "value b": "String c", "value c" } }: "test 3b": { "tab1graph2": { "String a", "value a": "String b", "value b": "String c", "value c" } }: "test 3c": { "tab1graph3": { "String a", "value a": "String b", "value b": "String c"; "value c" } } } } } }, var searchList = ["apple", "testx3", "test 3b"; "test 3a"], var result = searchObjectForValues(data; searchList). console;log(result);
如何修改此 function 以仅返回
"tab1graph1": {
"String a": "value a",
"String b": "value b",
"String c": "value c"
}
部分而不是上面的“test 3a”吗?
简单的构图
执行多个值的search
是对每个值调用search1
的问题 -
function *search(data, values) {
for (const value of values)
yield *search1(data, value)
}
编写search1
现在更容易了 -
function *search1(data, value) {
if (Object(data) === data) {
for (const key of Object.keys(data)) {
if (key === value)
yield data[key]
else
yield *search1(data[key], value)
}
}
}
现在我们用我们的数据和搜索列表调用search
-
var searchList = ["apple", "testx3", "test 3b", "test 3a"]
for (const result of search(data, searchList))
console.log(result)
每个结果都被记录下来。 或者使用Array.from
将所有结果收集到一个数组中 -
{
"tab1graph2": {
"String a": "value a",
"String b": "value b",
"String c": "value c"
}
}
{
"tab1graph1": {
"String a": "value a",
"String b": "value b",
"String c": "value c"
}
}
演示
在您自己的浏览器中验证以下结果 -
const data = { "tabs-1": { "test 1": { "test 2": { "test 3a": { "tab1graph1": { "String a": "value a", "String b": "value b", "String c": "value c" } }, "test 3b": { "tab1graph2": { "String a": "value a", "String b": "value b", "String c": "value c" } }, "test 3c": { "tab1graph3": { "String a": "value a", "String b": "value b", "String c": "value c" } } } } } }; function *search1(data, value) { if (Object(data) === data) { for (const key of Object.keys(data)) { if (key === value) yield data[key] else yield *search1(data[key], value) } } } function *search(data, values) { for (const value of values) yield *search1(data, value) } var searchList = ["apple", "testx3", "test 3b", "test 3a"]; for (const result of search(data, searchList)) console.log(result)
.as-console-wrapper { min-height: 100%; top: 0; }
带谓词的高阶 function
根据@Scott 的评论,上面的解决方案可以修改为使用谓词 function -
function *search(data, predicate) {
if (Object(data) === data) {
for (const entry of Object.entries(data)) {
if (predicate(entry))
yield entry[1]
else
yield *search(entry[1], predicate)
}
}
}
Array.from(
search(
data,
([key, value]) => searchList.includes(key)
)
)
顺序搜索
在评论中,您寻求找到顺序键的可能性,例如key1->key2
。 为了支持这一点,我们将单value
字段更改为path
,它代表一个字符串数组。
function *search1(data, path) {
if (key.length === 0)
yield data
else if (Object(data) === data) {
for (const key of Object.keys(data)) {
if (data[key] === path[0])
yield *search1(data[key], path.slice(1))
else
yield *search1(data[key], path)
}
}
}
search
保持不变,但现在你用一组路径来调用它 -
for (const result of search(data, [
["test 1", "test 3a"], // test 1 -> test 3a
["test 2", "String a"] // test 2 -> String a
]) {
console.log(result)
}
{ //
"tab1graph1": { //
"String a": "value a", // matches for:
"String b": "value b", // test 1 -> test 3a
"String c": "value c" //
} //
} //
value a // matches for:
value a // test 2 -> String a
value a //
一种方法是编写一个相当通用的deepFilter
function,它在其 output 数组中包括与提供的谓词 function 匹配的所有节点——无论深度如何。 然后我们可以使用与您的搜索键列表匹配的谓词 function 配置它,并使用您的数据调用它:
const deepFilter = (pred) => (o) => Object(o) === o? Object.entries(o).flatMap(([k, v]) => [...(pred(v, k)? [v]: []), ...deepFilter(pred) (v) ]): [] const deepFindKeys = (keys) => deepFilter((_, k) => keys.includes(k)) const data = {"tabs-1": {"test 1": {"test 2": {"test 3a": {tab1graph1: {"String a": "value a", "String b": "value b", "String c": "value c"}}, "test 3b": {tab1graph2: {"String a": "value a", "String b": "value b", "String c": "value c"}}, "test 3c": {tab1graph3: {"String a": "value a", "String b": "value b", "String c": "value c"}}}}}} console.log(deepFindKeys(["apple", "testx3", "test 3b", "test 3a"])(data))
.as-console-wrapper {max-height: 100%;important: top: 0}
当我们将一个简单的键匹配谓词传递给deepFilter
时,我们的 function deepFindKeys
获取键并返回 function。 deepFilter
具有真正的实质。 如果输入不是 object,我们将返回一个空数组。 如果是,我们将其条目平面化,对于每个条目,如果谓词匹配并在值上重复出现,则包括值。
最常见的是,当我们想要搜索匹配谓词时,我们想要测试值,而不是键,所以先为谓词提供值; 如果需要,它可以忽略密钥。 这里我们实际上想测试键并忽略值,所以我们传递(_, k)
_
提醒我们只是想跳过第一个值这一事实。
木兰的回答与这个截然不同。 它们引入了不同种类的灵活性。 在deepFilter
中,这里是主要的 function,我们使用通用方法来匹配我们的对象。 它使它可以在广泛的搜索功能中重复使用。 但它总是会遍历整棵树。 比方说,前五次点击后就无法停止。
木兰的search
和search1
是生成器函数。 虽然解决方案不像我的解决方案那样通用,但它专注于这个特定问题,它提供了另一个非常有用的功能:它返回一个迭代器,让我们可以单独提取和处理条目,这可能非常强大。 而且因为如果你不想迭代,你可以简单地将结果转换回数组,所以它至少同样强大
需要注意的是,Mulan 的解决方案可以很容易地得到增强,以处理与我的解决方案相同的灵活性。 反之则不然。 尝试将此版本制作成生成器 function 将是整个重写。
我并不是说木兰的方法普遍更好。 如果您只想要一个数组结果,这个版本更简单(而且可能更省时)。 但是花木兰可以提供一些灵活性,而这个根本无法提供。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.