9649


オブジェクトをシンタックス文字列によってフィルタリングする関数を作っています。

[code]

    obj =
      users: [
        {name:'takeda', age:'18'},
        {name:'kanako', age:'19'},
        {name:'sanada', age:'17'}
      ]
    
    objectFilter(obj, 'users[*].age') # -> {users:[{age:18}, {age:19}, {age:17}]}
    
[/code]

なんとか、頑張って以下のフィルタリング関数を作成することが出来ました。

**フィルタリング関数**

[code]

    window.objectFilter = (source, syntax)->
      recur = (src, obj, elems)->
        elems = _.cloneDeep(elems)
        # console.log _.cloneDeep(src), _.cloneDeep(obj), _.cloneDeep(elems)
        elem = elems.shift()
        return src if elem == undefined
        [key, idx] = elem.split(':')
        if idx == '*'
          if key == '*'
            for k of src
              obj[k] = obj[k] || []
              for i in [0...src?[k]?.length||0]
                obj[k].push recur(src?[k]?[i], obj[k][i], elems)
          else
            obj[key] = obj[key] || []
            for i in [0...src?[key]?.length||0]
              obj[key][i] = obj[key][i] || {}
              obj[key].push recur(src?[key]?[i], obj[key][i], elems)
        else if idx != undefined
          if key == '*'
            for k of src
              obj[k] = obj[k] || []
              obj[k].push src[k][idx]
          else
            obj[key] = obj[key] || []
            i = parseInt(idx)
            obj[key].push recur(src?[key]?[i], obj[key][i], elems) if src?[key]?[i]
        else
          if key == '*'
            obj = obj || {}
            for k of src
              obj[k] = obj[k] || {}
              obj[k] = recur(src?[k], obj[k], elems)
          else
            obj = obj || {}
            obj[key] = obj[key] || {}
            obj[key] = recur(src?[key], obj[key], elems)
        obj
    
      result = {}
      for v in syntax.replace(/[ ]/g,'').replace(/\]/g,'').replace(/\[/g,':').split(',')
        recur(source, result, v.split('.'))
      result
    
[/code]

そして、このフィルタリング関数をテストするために以下の複雑なオブジェクトを作成し実行します。

**フィルタリングするオブジェクト**

[code]

    obj =
      hoge: 'yeah!'
      fuga: {a:1, b:2, c:3}
      piyo: [
        {
          name:'takeshi'
          image: {src:'takeshi.png', info:'Smile of Takeshi'}
        },
        {
          name:'misako'
          image: {src:'misako001.png', info:'Angry of Misako'}
        },
        {
          name:'yusuke'
          image: {src:'3asdf_de.jpg', info:'happy yusuke'}
        }
      ]
      gaga: [{id:1, name:'michael'}, {id:2, name:'sally'}]
      pepe: {a:[1,2,3], b:[4,5,6], c:[7,8,9]}
      tata: {a:{token:'bdef', value:1}, b:{token:'gied', value:2}}
      kaka: {a:[{x:'1',y:'2'},{x:'3',y:'4'}], b:[{x:'5',y:'6'},{x:'7',y:'8'}]}
    
[/code]

シンタックスはカンマ区切りで複数指定することができる仕様になっています。

**実行**

[code]

    syntax = 'hoge, piyo[2].image.src, gaga[*].name, ora.ora, hena[*], tata.*.value, pepe.*[1], kaka.*[*].x'
    objectFilter(obj, syntax)
    
    # 結果
    # {
    #    hoge: 'yeah!',
    #    piyo: [ {image: {src: '3asdf_de.jpg'} ],
    #    gaga: [{name:'michael'}, {name:'sally'}],
    #    ora: {ora: null},
    #    hena: [],
    #    pepe: {a:[2], b:[5], c:[8]},
    #    tata: {a:{value:1}, b:{value:2}}
    #    kaka: {a:[{x:'1'},{x:'3'}], b:[{x:'5'},{x:'7'}]},
    # }
    
[/code]

恐らく、フィルタリング関数は以下のような条件を満たしているものになります。

  * syntax文字列はカンマ区切りによって複数指定できる
  * `piyo[2]`のようなシンタックスが指定された場合、配列とみなし3番目の要素にアクセスし、配列の要素数を1にする
  * `gaga[*]`や`pepe.*`のようなシンタックスが指定された場合コレクションの全要素を対象としてアクセスする
  * `ora.ora`のような存在しないオブジェクトが指定された場合、空のオブジェクトを作成する
  * `hena[*]`のような存在しない配列にアクセスが有った場合には空の配列を作成する
  * 指定したシンタックスの値がsourceオブジェクトに存在しなければnullを代入する

ちゃんと動作しているように思えます。

しかし、`objectFilter(obj,'piyo[*].*.src')`を実行したときのデータが正しく取得できませんでした、コードをなんども睨みつけて格闘しているのですが、どうも上手く動作してくれません。

[code]

    objectFilter(obj,'piyo[*].*.src')
    
    # 結果
    # 要素が3つから4つに増え、nameにsrc:undefinedが無く
    # image.srcの値が全て同じにものになってしまっている
    #
    # {
    #   piyo:[
    #     {name:{}, image:{src:"3asdf_de.jpg"}},
    #     {name:{}, image:{src:"3asdf_de.jpg"}},
    #     {name:{}, image:{src:"3asdf_de.jpg"}},
    #     {name:{}, image:{src:"3asdf_de.jpg"}}
    #   ]
    # }
    
[/code]

どこがおかしいのでしょうか？


CC BY-SA 3.0
2015-04-28T01:03:50.830
9623
2015-04-28T22:50:47.793
2015-04-28T22:44:28.800
5840
5840
question
javascript coffeescript
CoffeeScriptでJavascriptのオブジェクトをシンタックス文字列でフィルタリングする


以下の箇所を修正したら正しく動作しました。

![画像の説明をここに入力](https://i.stack.imgur.com/F3bhc.png)

最終的に出来上がったコードは以下になります

[code]

    window.objectFilter = (source, syntax)->
      recur = (src, obj, elems)->
        elems = _.clone(elems)
        elem = elems.shift()
        if elem == undefined
          src = null if src == undefined
          return src
        [key, idx] = elem.split(':')
        if idx == '*'
          if key == '*'
            for k of src
              obj[k] = obj[k] || []
              for i in [0...src?[k]?.length||0]
                obj[k][i] = recur(src?[k]?[i], obj[k][i], elems)
          else
            obj[key] = obj[key] || []
            for i in [0...src?[key]?.length||0]
              obj[key][i] = recur(src?[key]?[i], obj[key][i], elems)
        else if idx != undefined
          if key == '*'
            for k of src
              obj[k] = obj[k] || []
              obj[k][idx] = src[k][idx]
          else
            obj[key] = obj[key] || []
            i = parseInt(idx)
            obj[key][i] = recur(src?[key]?[i], obj[key][i], elems) if src?[key]?[i]
        else
          if key == '*'
            obj = obj || {}
            for k of src
              obj[k] = obj[k] || {}
              obj[k] = recur(src?[k], obj[k], elems)
          else
            obj = obj || {}
            obj[key] = obj[key] || {}
            obj[key] = recur(src?[key], obj[key], elems)
        obj
    
      result = {}
      for v in syntax.replace(/[ ]/g,'').replace(/\]/g,'').replace(/\[/g,':').split(',')
        recur(source, result, v.split('.'))
    
      do recur = (obj=result)->
        if _.isArray(obj) || _.isObject(obj)
          _.each obj, (v,k)->
            obj[k] = recur(v)
        obj = obj.filter((v)->v!=undefined) if _.isArray(obj)
        obj
    
[/code]

[こちら](http://jsfiddle.net/5kms9eq3/)にもサンプルを用意させていただきました。


CC BY-SA 3.0
2015-04-28T11:00:39.753
9649
2015-04-28T22:50:47.793
2015-04-28T22:50:47.793
5840
5840
9623
answer