Javascript嵌套对象到多维数组的递归函数

时间:2022-11-05 21:28:55

Ok here's one at which I've been scratching my head at without great success so far; Sorry in advance for the very long question...

好的,到目前为止,我一直在摸不着头脑;很抱歉这个很长的问题......

I am using this Lucene Query Parser to parse a string/query which produce this kind of data structure:

我使用这个Lucene Query Parser来解析产生这种数据结构的字符串/查询:

// Notice that the repetition of 'field3' is on purpose
Sample String: field1:val1 AND field2:val2 OR field3:val3 AND field3:val4
Result:
    { left: { field: "field1", term: "val1" },
      operator: "AND"
      right: {
          left: { field: "field2", term: "val2" },
          operator: "OR"
          right: { 
              left: {field: "field3", term: "val3" },
              operator: "AND",
              right: {
                   field: "field3",
                   term: "val4"
              }
          }
      }

I need to iterate on that object to obtain the following:

我需要迭代该对象以获取以下内容:

[ [{ field: "field1", term: "val1"},
   { field: "field2", term: "val2"}
  ],
  [{ field: "field3", term: "val3"},
   { field: "field3", term: "val4"}
  ]
]

If I try to explain this, the idea is to create an array of arrays where each child array are separated by "OR", while each objects inside the child arrays represents the "AND" separated fields; Although I think the code above explains it better than me

如果我试着解释一下,我的想法是创建一个数组数组,其中每个子数组用“OR”分隔,而子数组中的每个对象代表“AND”分​​隔的字段;虽然我认为上面的代码比我更好地解释了它

Updated code (coffeescript and lo-dash, sorry):

更新的代码(coffeescript和lo-dash,抱歉):

groups = []     
createGroups = (item, previousGroup, previousOperator) ->
    currentGroup = if _.isArray previousGroup then previousGroup else []

    # keyVal = {}
    # keyVal[item.left?.field or item.field] =  item.left?.term or item.term
    obj = fieldName: item.left?.field or item.field, val: item.left?.term or item.term

    if previousOperator?.toUpperCase() is 'AND'
        currentGroup.push obj
    else
        currentGroup = [obj]

    if _.isObject item.right
        createGroups(item.right, currentGroup, item.operator)

    groups.push currentGroup

This code works, and pretty much do what I want, but rely on the groups array to be declared outside the function (fine), but used as is directly inside the function, which is not quite ideal, but I can live with it.

这段代码很有用,几乎可以做我想要的,但依赖于groups数组在函数外部声明(精细),但直接在函数内部使用,这不是很理想,但我可以忍受它。

However, it will duplicate every groups like so:

但是,它将复制每个组,如下所示:

[ [ {field: "field1", val:val1}, {field: "field2" val:val2} ], [ {field: "field1":val1}, {field: "field2", val:val2} ], ...]

For now I have to use _.uniq(groups) which is an operation I shouldnt have to do, if the above function would return the correct results

现在我必须使用_.uniq(groups)这是一个我不应该做的操作,如果上面的函数会返回正确的结果

Thanks for your help

谢谢你的帮助

1 个解决方案

#1


1  

I think this ought to do it:

我认为应该这样做:

createGroups = (item, previousGroup) ->
  subroutine = (item, previousGroup) ->
    if typeof item is "object"
      unless item.operator
        if !item.left
          previousGroup.push item  
        else
          previousGroup.push item.left
        previousGroup
      if item.operator is "AND"
        currentGroup = subroutine(item.left, previousGroup)
        currentGroup = subroutine(item.right, currentGroup)
        currentGroup and groups.push(currentGroup)
      if item.operator is "OR"
        currentGroup = subroutine(item.left, previousGroup)
        groups.push currentGroup
        currentGroup and subroutine(item.right, [])
    return

  previousGroup = previousGroup or []
  subroutine item, previousGroup
  groups

createGroups o

#1


1  

I think this ought to do it:

我认为应该这样做:

createGroups = (item, previousGroup) ->
  subroutine = (item, previousGroup) ->
    if typeof item is "object"
      unless item.operator
        if !item.left
          previousGroup.push item  
        else
          previousGroup.push item.left
        previousGroup
      if item.operator is "AND"
        currentGroup = subroutine(item.left, previousGroup)
        currentGroup = subroutine(item.right, currentGroup)
        currentGroup and groups.push(currentGroup)
      if item.operator is "OR"
        currentGroup = subroutine(item.left, previousGroup)
        groups.push currentGroup
        currentGroup and subroutine(item.right, [])
    return

  previousGroup = previousGroup or []
  subroutine item, previousGroup
  groups

createGroups o