javascript 按嵌套数组深处的键查找
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15523514/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Find by key deep in a nested array
提问by Harry
Let's say I have an object:
假设我有一个对象:
[
{
'title': "some title"
'channel_id':'123we'
'options': [
{
'channel_id':'abc'
'image':'http://asdasd.com/all-inclusive-block-img.jpg'
'title':'All-Inclusive'
'options':[
{
'channel_id':'dsa2'
'title':'Some Recommends'
'options':[
{
'image':'http://www.asdasd.com' 'title':'Sandals'
'id':'1'
'content':{
...
I want to find the one object where the id is 1. Is there a function for something like this? I could use Underscore's _.filter
method, but I would have to start at the top and filter down.
我想找到一个 id 为 1 的对象。有这样的函数吗?我可以使用 Underscore 的_.filter
方法,但我必须从顶部开始并向下过滤。
回答by Zach
Recursion is your friend. I updated the function to account for property arrays:
递归是你的朋友。我更新了函数以说明属性数组:
function getObject(theObject) {
var result = null;
if(theObject instanceof Array) {
for(var i = 0; i < theObject.length; i++) {
result = getObject(theObject[i]);
if (result) {
break;
}
}
}
else
{
for(var prop in theObject) {
console.log(prop + ': ' + theObject[prop]);
if(prop == 'id') {
if(theObject[prop] == 1) {
return theObject;
}
}
if(theObject[prop] instanceof Object || theObject[prop] instanceof Array) {
result = getObject(theObject[prop]);
if (result) {
break;
}
}
}
}
return result;
}
updated jsFiddle: http://jsfiddle.net/FM3qu/7/
更新 jsFiddle:http: //jsfiddle.net/FM3qu/7/
回答by haitaka
If you want to get the first element whose id is 1 while object is being searched, you can use this function:
如果要在搜索对象时获取第一个 id 为 1 的元素,可以使用此函数:
function customFilter(object){
if(object.hasOwnProperty('id') && object["id"] == 1)
return object;
for(var i=0; i<Object.keys(object).length; i++){
if(typeof object[Object.keys(object)[i]] == "object"){
var o = customFilter(object[Object.keys(object)[i]]);
if(o != null)
return o;
}
}
return null;
}
If you want to get all elements whose id is 1, then (all elements whose id is 1 are stored in result as you see):
如果要获取所有 id 为 1 的元素,则(如您所见,所有 id 为 1 的元素都存储在结果中):
function customFilter(object, result){
if(object.hasOwnProperty('id') && object.id == 1)
result.push(object);
for(var i=0; i<Object.keys(object).length; i++){
if(typeof object[Object.keys(object)[i]] == "object"){
customFilter(object[Object.keys(object)[i]], result);
}
}
}
回答by abhinav1602
What worked for me was this lazy approach, not algorithmically lazy ;)
对我有用的是这种懒惰的方法,而不是算法上的懒惰;)
if( JSON.stringify(object_name).indexOf("key_name") > -1 ) {
console.log("Key Found");
}
else{
console.log("Key not Found");
}
回答by Alex Quan
I found this page through googling for the similar functionalities. Based on the work provided by Zach and regularmike, I created another version which suits my needs.
BTW, teriffic work Zah and regularmike!
I'll post the code here:
我通过谷歌搜索类似的功能找到了这个页面。基于 Zach 和 regularmike 提供的工作,我创建了另一个适合我需要的版本。
顺便说一句,Zah 和regularmike 干得好!我会在这里发布代码:
function findObjects(obj, targetProp, targetValue, finalResults) {
function getObject(theObject) {
let result = null;
if (theObject instanceof Array) {
for (let i = 0; i < theObject.length; i++) {
getObject(theObject[i]);
}
}
else {
for (let prop in theObject) {
if(theObject.hasOwnProperty(prop)){
console.log(prop + ': ' + theObject[prop]);
if (prop === targetProp) {
console.log('--found id');
if (theObject[prop] === targetValue) {
console.log('----found porop', prop, ', ', theObject[prop]);
finalResults.push(theObject);
}
}
if (theObject[prop] instanceof Object || theObject[prop] instanceof Array){
getObject(theObject[prop]);
}
}
}
}
}
getObject(obj);
}
What it does is it find any object inside of obj
with property name and value matching to targetProp
and targetValue
and will push it to the finalResults
array.
And Here's the jsfiddle to play around:
https://jsfiddle.net/alexQch/5u6q2ybc/
它的作用是找到其中的任何对象,obj
其属性名称和值与targetProp
和匹配targetValue
,并将其推送到finalResults
数组中。这是要玩的 jsfiddle:https://jsfiddle.net/alexQch/5u6q2ybc/
回答by Iulian Pinzaru
Improved @haitaka answer, using the key and predicate
使用键和谓词改进了@haitaka 答案
function deepSearch (object, key, predicate) {
if (object.hasOwnProperty(key) && predicate(key, object[key]) === true) return object
for (let i = 0; i < Object.keys(object).length; i++) {
if (typeof object[Object.keys(object)[i]] === "object") {
let o = deepSearch(object[Object.keys(object)[i]], key, predicate)
if (o != null) return o
}
}
return null
}
So this can be invoked as:
所以这可以被调用为:
var result = deepSearch(myObject, 'id', (k, v) => v === 1);
or
或者
var result = deepSearch(myObject, 'title', (k, v) => v === 'Some Recommends');
Here is the jsFiddle: http://jsfiddle.net/ktdx9es7
这是 jsFiddle:http: //jsfiddle.net/ktdx9es7
回答by dominik791
I've created library for this purpose: https://github.com/dominik791/obj-traverse
我为此目的创建了库:https: //github.com/dominik791/obj-traverse
You can use findFirst()
method like this:
您可以使用这样的findFirst()
方法:
var foundObject = findFirst(rootObject, 'options', { 'id': '1' });
And now foundObject
variable stores a reference to the object that you're looking for.
现在foundObject
变量存储对您正在寻找的对象的引用。
回答by CertainPerformance
Another (somewhat silly) option is to exploit the naturally recursive nature of JSON.stringify
, and pass it a replacer functionwhich runs on each nested object during the stringification process:
另一个(有点愚蠢的)选项是利用 的自然递归性质JSON.stringify
,并在字符串化过程中向它传递一个在每个嵌套对象上运行的替换函数:
const input = [{
'title': "some title",
'channel_id': '123we',
'options': [{
'channel_id': 'abc',
'image': 'http://asdasd.com/all-inclusive-block-img.jpg',
'title': 'All-Inclusive',
'options': [{
'channel_id': 'dsa2',
'title': 'Some Recommends',
'options': [{
'image': 'http://www.asdasd.com',
'title': 'Sandals',
'id': '1',
'content': {}
}]
}]
}]
}];
console.log(findNestedObj(input, 'id', '1'));
function findNestedObj(entireObj, keyToFind, valToFind) {
let foundObj;
JSON.stringify(input, (_, nestedValue) => {
if (nestedValue && nestedValue[keyToFind] === valToFind) {
foundObj = nestedValue;
}
return nestedValue;
});
return foundObj;
};
回答by Villarrealized
@Iulian Pinzaru's answer was almost exactly what I needed, but it doesn't work if your objects have any null values. This version fixes that.
@Iulian Pinzaru 的答案几乎正是我所需要的,但如果您的对象具有任何空值,则它不起作用。这个版本解决了这个问题。
function deepSearch (object, key, predicate) {
if (object.hasOwnProperty(key) && predicate(key, object[key]) === true) return object
for (let i = 0; i < Object.keys(object).length; i++) {
const nextObject = object[Object.keys(object)[i]];
if (nextObject && typeof nextObject === "object") {
let o = deepSearch(nextObject, key, predicate)
if (o != null) return o
}
}
return null
}
回答by Arfeo
Some time ago I have made a small lib find-and
, which is available on npm, for working with nested objects in a lodash manner. There's the returnFound
function which returns the found object, or an object array if there's more than one object found.
前段时间我制作了一个小的 lib find-and
,它在npm上可用,用于以 lodash 方式处理嵌套对象。有returnFound
返回找到的对象的函数,如果找到多个对象,则返回对象数组。
E.g.,
例如,
const findAnd = require('find-and');
const a = [
{
'title': "some title",
'channel_id':'123we',
'options': [
{
'channel_id':'abc',
'image':'http://asdasd.com/all-inclusive-block-img.jpg',
'title':'All-Inclusive',
'options':[
{
'channel_id':'dsa2',
'title':'Some Recommends',
'options':[
{
'image':'http://www.asdasd.com',
'title':'Sandals',
'id':'1',
'content':{},
},
],
},
],
},
],
},
];
findAnd.returnFound(a, {id: '1'});
returns
回报
{
'image':'http://www.asdasd.com',
'title':'Sandals',
'id':'1',
'content':{},
}
回答by Richard T
I'd like to suggest an amendment to Zach/RegularMike's answer (but don't have the "reputation" to be able to comment!). I found there solution a very useful basis, but suffered in my application because if there are strings within arrays it would recursively call the function for every characterin the string (which caused IE11 & Edge browsers to fail with "out of stack space" errors). My simple optimization was to add the same test used in the "object" clause recursive call to the one in the "array" clause:
我想建议对 Zach/RegularMike 的回答进行修正(但没有“声誉”可以发表评论!)。我发现那里的解决方案是一个非常有用的基础,但在我的应用程序中受到影响,因为如果数组中有字符串,它会为字符串中的每个字符递归调用该函数(这导致 IE11 和 Edge 浏览器因“堆栈空间不足”错误而失败) )。我的简单优化是将“object”子句递归调用中使用的相同测试添加到“array”子句中的测试:
if (arrayElem instanceof Object || arrayElem instanceof Array) {
Thus my full code (which is now looking for all instances of a particular key, so slightly different to the original requirement) is:
因此,我的完整代码(现在正在查找特定键的所有实例,与原始要求略有不同)是:
// Get all instances of specified property deep within supplied object
function getPropsInObject(theObject, targetProp) {
var result = [];
if (theObject instanceof Array) {
for (var i = 0; i < theObject.length; i++) {
var arrayElem = theObject[i];
if (arrayElem instanceof Object || arrayElem instanceof Array) {
result = result.concat(getPropsInObject(arrayElem, targetProp));
}
}
} else {
for (var prop in theObject) {
var objProp = theObject[prop];
if (prop == targetProp) {
return theObject[prop];
}
if (objProp instanceof Object || objProp instanceof Array) {
result = result.concat(getPropsInObject(objProp, targetProp));
}
}
}
return result;
}