[英]Find by key deep in a nested array
假設我有一個 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':{
...
我想找到一個 ID 為 1 的 object。是否有這樣的 function ? 我可以使用 Underscore 的_.filter
方法,但我必須從頂部開始向下過濾。
遞歸是你的朋友。 我更新了函數以說明屬性數組:
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;
}
更新 jsFiddle: http : //jsfiddle.net/FM3qu/7/
對我有用的是這種懶惰的方法,而不是算法上的懶惰;)
if( JSON.stringify(object_name).indexOf("key_name") > -1 ) {
console.log("Key Found");
}
else{
console.log("Key not Found");
}
如果要在搜索對象時獲取第一個 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;
}
如果要獲取所有 id 為 1 的元素,則(如您所見,所有 id 為 1 的元素都存儲在 result 中):
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);
}
}
}
另一個(有點傻)的選擇是利用JSON.stringify
的自然遞歸特性,並在字符串化過程中向它傳遞一個在每個嵌套對象上運行的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(entireObj, (_, nestedValue) => { if (nestedValue && nestedValue[keyToFind] === valToFind) { foundObj = nestedValue; } return nestedValue; }); return foundObj; };
我通過谷歌搜索類似的功能找到了這個頁面。 基於 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);
}
它所做的是找到它的任何對象內部obj
與屬性名稱和值匹配targetProp
和targetValue
,並將它推到finalResults
陣列。 這是要玩的 jsfiddle: https ://jsfiddle.net/alexQch/5u6q2ybc/
我為此目的創建了庫: https : //github.com/dominik791/obj-traverse
您可以像這樣使用findFirst()
方法:
var foundObject = findFirst(rootObject, 'options', { 'id': '1' });
現在foundObject
變量存儲對您正在尋找的對象的引用。
使用鍵和謂詞改進了@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++) {
let value = object[Object.keys(object)[i]];
if (typeof value === "object" && value != null) {
let o = deepSearch(object[Object.keys(object)[i]], key, predicate)
if (o != null) return o
}
}
return null
}
所以這可以被調用為:
var result = deepSearch(myObject, 'id', (k, v) => v === 1);
要么
var result = deepSearch(myObject, 'title', (k, v) => v === 'Some Recommends');
這是演示: http : //jsfiddle.net/a21dx6c0/
已編輯
以同樣的方式,您可以找到多個對象
function deepSearchItems(object, key, predicate) {
let ret = [];
if (object.hasOwnProperty(key) && predicate(key, object[key]) === true) {
ret = [...ret, object];
}
if (Object.keys(object).length) {
for (let i = 0; i < Object.keys(object).length; i++) {
let value = object[Object.keys(object)[i]];
if (typeof value === "object" && value != null) {
let o = this.deepSearchItems(object[Object.keys(object)[i]], key, predicate);
if (o != null && o instanceof Array) {
ret = [...ret, ...o];
}
}
}
}
return ret;
}
我們使用對象掃描進行數據處理。 它在概念上非常簡單,但允許很多很酷的東西。 以下是您解決具體問題的方法
// const objectScan = require('object-scan'); const find = (id, input) => objectScan(['**'], { abort: true, rtn: 'value', filterFn: ({ value }) => value.id === id })(input); const data = [{ 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(find('1', data)); // => { image: 'http://www.asdasd.com', title: 'Sandals', id: '1', content: {} }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>
免責聲明:我是對象掃描的作者
@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
}
另一個遞歸解決方案,適用於數組/列表和對象,或兩者的混合:
function deepSearchByKey(object, originalKey, matches = []) {
if(object != null) {
if(Array.isArray(object)) {
for(let arrayItem of object) {
deepSearchByKey(arrayItem, originalKey, matches);
}
} else if(typeof object == 'object') {
for(let key of Object.keys(object)) {
if(key == originalKey) {
matches.push(object);
} else {
deepSearchByKey(object[key], originalKey, matches);
}
}
}
}
return matches;
}
用法:
let result = deepSearchByKey(arrayOrObject, 'key'); // returns an array with the objects containing the key
改進的答案以考慮對象內的循環引用。 它還顯示到達那里的路徑。
在此示例中,我正在搜索我知道位於全局對象中某處的 iframe:
const objDone = []
var i = 2
function getObject(theObject, k) {
if (i < 1 || objDone.indexOf(theObject) > -1) return
objDone.push(theObject)
var result = null;
if(theObject instanceof Array) {
for(var i = 0; i < theObject.length; i++) {
result = getObject(theObject[i], i);
if (result) {
break;
}
}
}
else
{
for(var prop in theObject) {
if(prop == 'iframe' && theObject[prop]) {
i--;
console.log('iframe', theObject[prop])
return theObject[prop]
}
if(theObject[prop] instanceof Object || theObject[prop] instanceof Array) {
result = getObject(theObject[prop], prop);
if (result) {
break;
}
}
}
}
if (result) console.info(k)
return result;
}
運行以下命令: getObject(reader, 'reader')
給出了以下輸出和 iframe 元素:
iframe // (The Dom Element)
_views
views
manager
rendition
book
reader
注意:路徑是逆序的reader.book.rendition.manager.views._views.iframe
我想建議對 Zach/RegularMike 的回答進行修正(但沒有“聲譽”可以發表評論!)。 我發現那里的解決方案是一個非常有用的基礎,但在我的應用程序中受到影響,因為如果數組中有字符串,它會為字符串中的每個字符遞歸調用該函數(這導致 IE11 和 Edge 瀏覽器因“堆棧空間不足”錯誤而失敗)。 我的簡單優化是將“object”子句遞歸調用中使用的相同測試添加到“array”子句中的測試:
if (arrayElem instanceof Object || arrayElem instanceof Array) {
因此,我的完整代碼(現在正在查找特定鍵的所有實例,與原始要求略有不同)是:
// 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;
}
前段時間我制作了一個小的 lib find-and
,它在npm上可用,用於以 lodash 方式處理嵌套對象。 有returnFound
函數返回找到的對象,如果找到多個對象,則返回一個對象數組。
例如,
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'});
返回
{
'image':'http://www.asdasd.com',
'title':'Sandals',
'id':'1',
'content':{},
}
只需使用遞歸函數。
請參閱下面的示例:
const data = [ { 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: {}, } ] } ] } ] } ] function _find(collection, key, value) { for (const o of collection) { for (const [k, v] of Object.entries(o)) { if (k === key && v === value) { return o } if (Array.isArray(v)) { const _o = _find(v, key, value) if (_o) { return _o } } } } } console.log(_find(data, 'channel_id', 'dsa2'))
您可以在遞歸函數中使用 javascript some
函數。 some 的優點是一旦孩子被建立就停止循環。 不要使用在大數據中會變慢的地圖。
const findChild = (array, id) => {
let result;
array.some(
(child) =>
(child.id === id && (result = child)) ||
(result = findChild(child.options || [], id))
);
return result;
};
findNode(array, 1)
function getPropFromObj(obj, prop) { let valueToFindByKey; if (!Array.isArray(obj) && obj !== null && typeof obj === "object") { if (obj.hasOwnProperty(prop)) { valueToFindByKey = obj[prop]; console.log(valueToFindByKey); } else { let i; for (i = 0; i < Object.keys(obj).length; i++) { getPropFromObj(obj[Object.keys(obj)[i]], prop); } } } return null; } const objToInvestigate = { employeeInformation: { employees: { name: "surya", age: 27, job: "Frontend Developer", }, }, }; getPropFromObj(objToInvestigate, "name");
找到了我正在尋找的答案,尤其是 Ali Alnoaimi 的解決方案。 我做了一些小的調整以允許搜索值
function deepSearchByKey(object, originalKey, originalValue, matches = []) {
if (object != null) {
if (Array.isArray(object)) {
for (let arrayItem of object) {
deepSearchByKey(arrayItem, originalKey, originalValue, matches);
}
} else if (typeof object == 'object') {
for (let key of Object.keys(object)) {
if (key == originalKey) {
if (object[key] == originalValue) {
matches.push(object);
}
} else {
deepSearchByKey(object[key], originalKey, originalValue, matches);
}
}
}
}
return matches;
}
要使用:
let result = deepSearchByKey(arrayOrObject, 'key', 'value');
這將返回包含匹配鍵和值的 object。
fucntion getPath(obj, path, index = 0) { const nestedKeys = path.split('.') const selectedKey = nestedKeys[index] if (index === nestedKeys.length - 1) { return obj[selectedKey] } if (!obj.hasOwnProperty(selectedKey)) { return {} } const nextObj = obj[selectedKey] return Utils.hasPath(nextObj, path, index + 1) }
不客氣 作者:Gorillaz
如果你對整個 ES6 感興趣,你可以使用
const findByKey = (obj, kee) => {
if (kee in obj) return obj[kee];
for(n of Object.values(obj).filter(Boolean).filter(v => typeof v === 'object')) {
let found = findByKey(n, kee)
if (found) return found
}
}
const arry = [{ foo: 0 }, null, { bar: [{ baz: { nutherKey: undefined, needle: "gotcha!" } }]}]
const obj = { alice: Infinity, bob: NaN, charlie: "string", david: true, ebert: arry }
findByKey(obj, 'needle')
// 'gotcha!'
如何搜索測試 5 或測試 3 嵌套值以及它們是否存在返回“名稱”值。
{
name: 'Test1',
info: {
Test 1: 'Test 1',
'Test 3': 'Testing 3',
'Test 4': 'Testing 4',
Test 5: 'Testing 5'
},
name: 'Test2',
info: {
Test 1: 'Test 1',
'Test 3': 'Testing 3',
'Test 4': 'Testing 4',
Test 5: ''
},
}
這段代碼允許您獲取 JSON 中的所有對象,其鍵是用戶定義的。
function main(obj = {}, property){
const views = [];
function traverse(o) {
for (var i in o) {
if(i === property) views.push(o[i]);
if (!!o[i] && typeof(o[i])=="object") {
console.log(i, o[i]);
traverse(o[i]);
} else {
console.log(i, o[i]);
}
}
}
traverse(obj);
return views;
}
下面是一個例子:
const obj = {
id: 'id at level 1',
level2: {
id: 'id at level 2',
level3: {
id: 'id at level 3',
level4: {
level5: {
id: 'id at level 5'
}
}
}
},
text: ''
}
main(obj, 'id');
如果您已經在使用 Underscore,請使用 _.find()
_.find(yourList, function (item) {
return item.id === 1;
});
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.