45

私は膨大なコレクションを持っており、コレクション内のどこかでキーでプロパティを探しています。そのキー/インデックスを含むすべてのオブジェクトへの参照またはフルパスのリストを取得するための信頼できる方法は何ですか?役立つ場合はjQueryとlodashを使用しますが、無限ポインターの再帰を忘れることができます。これは純粋なJSON応答です。

fn({ 'a': 1, 'b': 2, 'c': {'d':{'e':7}}}, "d"); 
// [o.c]

fn({ 'a': 1, 'b': 2, 'c': {'d':{'e':7}}}, "e");
// [o.c.d]

fn({ 'aa': 1, 'bb': 2, 'cc': {'d':{'x':9}}, dd:{'d':{'y':9}}}, 'd');
// [o.cc,o.cc.dd]

fwiw lodashには、2つのネストの深さのネストされたオブジェクトを検索する_.find関数がありますが、その後は失敗するようです。(例: http: //codepen.io/anon/pen/bnqyh

4

10 に答える 10

50

これはそれを行う必要があります:

function fn(obj, key) {
    if (_.has(obj, key)) // or just (key in obj)
        return [obj];
    // elegant:
    return _.flatten(_.map(obj, function(v) {
        return typeof v == "object" ? fn(v, key) : [];
    }), true);

    // or efficient:
    var res = [];
    _.forEach(obj, function(v) {
        if (typeof v == "object" && (v = fn(v, key)).length)
            res.push.apply(res, v);
    });
    return res;
}
于 2013-03-26T17:15:16.197 に答える
24

純粋なJavaScriptソリューションは次のようになります。

function findNested(obj, key, memo) {
  var i,
      proto = Object.prototype,
      ts = proto.toString,
      hasOwn = proto.hasOwnProperty.bind(obj);

  if ('[object Array]' !== ts.call(memo)) memo = [];

  for (i in obj) {
    if (hasOwn(i)) {
      if (i === key) {
        memo.push(obj[i]);
      } else if ('[object Array]' === ts.call(obj[i]) || '[object Object]' === ts.call(obj[i])) {
        findNested(obj[i], key, memo);
      }
    }
  }

  return memo;
}

この関数の使用方法は次のとおりです。

findNested({'aa': 1, 'bb': 2, 'cc': {'d':{'x':9}}, dd:{'d':{'y':9}}}, 'd');

結果は次のようになります。

[{x: 9}, {y: 9}]
于 2013-03-26T17:15:15.160 に答える
5

これにより、オブジェクトの配列(hay)で値(needle)が深く検索され、結果を含む配列が返されます。

search = function(hay, needle, accumulator) {
  var accumulator = accumulator || [];
  if (typeof hay == 'object') {
    for (var i in hay) {
      search(hay[i], needle, accumulator) == true ? accumulator.push(hay) : 1;
    }
  }
  return new RegExp(needle).test(hay) || accumulator;
}
于 2015-02-24T15:46:47.770 に答える
3

プレーンJS(またはlodashの組み合わせ)で再帰関数を記述できる場合(パフォーマンスの点で)、それが最良の関数になりますが、再帰を自分の側からスキップして、単純で読み取り可能なコードを使用したい場合(パフォーマンスに応じて最適です)次に、オブジェクトを再帰的にトラバースする必要があるあらゆる目的にlodash#cloneDeepWithを使用できます。

let findValuesDeepByKey = (obj, key, res = []) => (
    _.cloneDeepWith(obj, (v,k) => {k==key && res.push(v)}) && res
)

したがって、の2番目の引数として渡すコールバックは、すべてのペア_.cloneDeepWithを再帰的にトラバースします。必要なのは、それぞれで実行する操作だけです。key/value上記のコードはあなたのケースのほんの一例です。実例は次のとおりです。

var object = {
    prop1: 'ABC1',
    prop2: 'ABC2',
    prop3: {
        prop4: 'ABC3',
        prop5Arr: [{
                prop5: 'XYZ'
            },
            {
                prop5: 'ABC4'
            },
            {
                prop6: {
                    prop6NestedArr: [{
                            prop1: 'XYZ Nested Arr'
                        },
                        {
                            propFurtherNested: {key100: '100 Value'}
                        }
                    ]
                }
            }
        ]
    }
}
let findValuesDeepByKey = (obj, key, res = []) => (
    _.cloneDeepWith(obj, (v,k) => {k==key && res.push(v)}) && res
)

console.log(findValuesDeepByKey(object, 'prop1'));
console.log(findValuesDeepByKey(object, 'prop5'));
console.log(findValuesDeepByKey(object, 'key100'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

于 2018-08-04T19:37:12.290 に答える
3

Deepdashを使用すると、 PickDeepを選択してそこからパスを取得したり、インデックスを作成したりできます(パスの作成->値オブジェクト)

var obj = { 'aa': 1, 'bb': 2, 'cc': {'d':{'x':9}}, dd:{'d':{'y':9}}}

var cherry = _.pickDeep(obj,"d");

console.log(JSON.stringify(cherry));
// {"cc":{"d":{}},"dd":{"d":{}}}

var paths = _.paths(cherry);

console.log(paths);
// ["cc.d", "dd.d"]

paths = _.paths(cherry,{pathFormat:'array'});

console.log(JSON.stringify(paths));
// [["cc","d"],["dd","d"]]

var index = _.indexate(cherry);

console.log(JSON.stringify(index));
// {"cc.d":{},"dd.d":{}}

これがCodepenのデモです

于 2019-03-11T09:12:07.123 に答える
2

このようなものが機能し、それをオブジェクトに変換して再帰します。

function find(jsonStr, searchkey) {
    var jsObj = JSON.parse(jsonStr);
    var set = [];
    function fn(obj, key, path) {
        for (var prop in obj) {
            if (prop === key) {
                set.push(path + "." + prop);
            }
            if (obj[prop]) {
                fn(obj[prop], key, path + "." + prop);
            }
        }
        return set;
    }
    fn(jsObj, searchkey, "o");
}

フィドル:jsfiddle

于 2013-03-26T16:58:22.560 に答える
1

@eugeneからの更新された回答が表示されない場合は、この調整により、検索するキーのリストを渡すことができます。

// Method that will find any "message" in the Apex errors that come back after insert attempts
// Could be a validation rule, or duplicate record, or pagemessage.. who knows!
// Use in your next error toast from a wire or imperative catch path!   
// message: JSON.stringify(this.findNested(error, ['message', 'stackTrace'])),
// Testing multiple keys: this.findNested({thing: 0, list: [{message: 'm'}, {stackTrace: 'st'}], message: 'm2'}, ['message', 'stackTrace'])
findNested(obj, keys, memo) {
    let i,
        proto = Object.prototype,
        ts = proto.toString,
        hasOwn = proto.hasOwnProperty.bind(obj);
  
    if ('[object Array]' !== ts.call(memo)) memo = [];
  
    for (i in obj) {
      if (hasOwn(i)) {
        if (keys.includes(i)) {
          memo.push(obj[i]);
        } else if ('[object Array]' === ts.call(obj[i]) || '[object Object]' === ts.call(obj[i])) {
          this.findNested(obj[i], keys, memo);
        }
      }
    }
  
    return memo.length == 0 ? null : memo;
}
于 2020-10-01T19:42:59.560 に答える
0
Array.prototype.findpath = function(item,path) {
  return this.find(function(f){return item==eval('f.'+path)});
}
于 2016-11-17T15:45:48.077 に答える
0

これが私がそれをした方法です:

function _find( obj, field, results )
{
    var tokens = field.split( '.' );

    // if this is an array, recursively call for each row in the array
    if( obj instanceof Array )
    {
        obj.forEach( function( row )
        {
            _find( row, field, results );
        } );
    }
    else
    {
        // if obj contains the field
        if( obj[ tokens[ 0 ] ] !== undefined )
        {
            // if we're at the end of the dot path
            if( tokens.length === 1 )
            {
                results.push( obj[ tokens[ 0 ] ] );
            }
            else
            {
                // keep going down the dot path
                _find( obj[ tokens[ 0 ] ], field.substr( field.indexOf( '.' ) + 1 ), results );
            }
        }
    }
}

それをテストする:

var obj = {
    document: {
        payload: {
            items:[
                {field1: 123},
                {field1: 456}
                ]
        }
    }
};
var results = [];

_find(obj.document,'payload.items.field1', results);
console.log(results);

出力

[ 123, 456 ]
于 2016-11-29T01:00:15.307 に答える
0

データ処理タスクにはオブジェクトスキャンを使用します。使い方に頭を悩ませたら、すごいです。

// const objectScan = require('object-scan');

const haystack = { a: { b: { c: 'd' }, e: { f: 'g' } } };
const r = objectScan(['a.*.*'], { joined: true, rtn: 'entry' })(haystack);
console.log(r);
// => [ [ 'a.e.f', 'g' ], [ 'a.b.c', 'd' ] ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>

免責事項:私はオブジェクトスキャンの作成者です

ウェブサイトにはもっとたくさんの例があります。

于 2020-10-25T03:35:48.750 に答える