根据另一个对象过滤对象

时间:2020-03-06 17:59:41

标签: javascript object

我想基于另一个对象中的点符号字符串来转换对象。例如:

const objToTransform = {
  "a": "aValue",
  "b": {
      "c": "cValue",
      "d": "dValue"
  }
};

const filteringObj = {
  "field1": "a",
  "field2": {
    "subfield1": "b.c",
    "subfield2": "b.d"
  }
};

const filteredObj = myFunc(objToTransform, filteringObj);
// expect outputs to be: 
//  {
//   "field1": "aValue",
//   "field2": {
//      "subfield1": "cValue",
//      "subfield2": "dValue"
//    }
//  }

我已经在这个看似简单的事情上工作了几个小时,但仍然无法正常工作。我发现了this topic,它向您展示了如何使用点符号字符串获取嵌套的对象值,但又很难过。

在此先感谢您的帮助!

5 个答案:

答案 0 :(得分:0)

您可以使用递归在以下步骤中进行操作:

  • 复制filteringObj
  • 创建辅助函数getByPath,该函数获取对象和路径并从嵌套对象返回该路径处的值
  • 创建一个函数transform,该函数遍历filteringObj的键(我在函数中将其命名为pattern
  • 在循环中检查value是否是一个对象,然后对该子对象递归调用transform函数
  • 如果它不是对象,则使用objectToTransform函数从原始对象getByPath获取值

const objToTransform = {
  "a": "aValue",
  "b": {
      "c": "cValue",
      "d": "dValue"
  }
};

const filteringObj = {
  "field1": "a",
  "field2": {
    "subfield1": "b.c",
    "subfield2": "b.d"
  }
};

function getByPath(obj, path){
  //console.log(path)
  return path.split('.').reduce((ac,a) => ac[a], obj);
}

function transform(obj, pattern){
  for(let key in pattern){
    if(typeof pattern[key] === "object"){
      transform(obj, pattern[key]);
    }
    else{
      pattern[key] = getByPath(obj, pattern[key]);
    }
  }
}
const copy = JSON.parse(JSON.stringify(filteringObj))
transform(objToTransform, copy);
console.log(copy)

答案 1 :(得分:0)

您可以使用Mono.fromSupplier(() -> StringUtils.isEmailValid(signInRequest.getUserName())) .filter(o -> o) .flatMap(o -> userService.findByEmail(signInRequest.getUserName())) .switchIfEmpty(userService.findByUsername(signInRequest.getUserName())) ... 方法创建递归函数,该方法每次在值的类型为object时都会创建递归调用。

reduce

答案 2 :(得分:0)

我做了一个递归算法:

library(shiny)
library(shinyjs)

ui <- fluidPage(
  actionButton("do", "Click Me"),
  verbatimTextOutput("eventTimeRemaining"),
  imageOutput("msg")
)

server <- function(input, output, session) {

  EventTime <- reactiveVal(Sys.time())

  observeEvent(input$do,{
    EventTime(Sys.time() + 3)
  })

  timeLeft <- reactive({
    tl <- round(difftime(EventTime(), Sys.time(), units='secs'))
    if (tl > 0) {
      invalidateLater(1000, session)
    } 
    tl
  })

  output$eventTimeRemaining <- renderText({
    timeLeft()
  })

  output$msg <- renderImage({
    if (timeLeft() > 0) {
      list(src = '')
    } else {
      list(src = './sing.jpg')
    }
  }, deleteFile = FALSE)
}

shinyApp(ui, server)

答案 3 :(得分:0)

Lodash使您可以非常轻松地使用点表示法。 这正是您想要的(<10行):

import _ from "lodash";

const objToTransform = {
    a: "aValue",
    b: {
        c: "cValue",
        d: "dValue"
    }
};

const filteringObj = {
    field1: "a",
    field2: {
        subfield1: "b.c",
        subfield2: "b.d"
    }
};

const filter = (model, data, filtered = {}) => {
    for (const field in model) {
        filtered[field] =
            typeof model[field] === "object"
                ? filter(model[field], data, model[field])
                : _.get(objToTransform, model[field]);
    }
    return filtered;
};

console.log(filter(filteringObj, objToTransform))

答案 4 :(得分:0)

如果您正在使用(或有兴趣使用)Ramda(免责声明:如果我是其主要作者之一),那么这可能对您有用。 Ramda没有deepMap函数,但是编写函数很容易。并使用它,您的转换函数是一线的:

const deepMap = (fn) => (obj) => 
  is (Object, obj) ? map (deepMap (fn)) (obj) : fn (obj)

const transform = compose(applySpec, deepMap (compose (path, split('.'))))

const objToTransform = {a: "aValue", b: {c: "cValue", d: "dValue"}}
const filteringObj = {field1: "a", field2: {subfield1: "b.c", subfield2: "b.d"}}

console .log (transform (filteringObj) (objToTransform))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js"></script>
<script> const {is, map, compose, applySpec, path, split } = R       </script>

这里的关键点是applySpec,您可以直接使用filteringObj稍有不同的格式。这将产生您想要的结果:

applySpec ({
  field1: path (["a"]), 
  field2: {
    subfield1: path (["b", "c"]), 
    subfield2: path (["b", "d"])
  }
}) (objToTransform)

transform函数的其余部分只是将filteringObj转换为上面的形式。

如果您要继续按照问题中的要求来调用它,即使用transform (objToTransform, filteringObj)而不是trasform (filteringObj) (objToTransform),则只会稍微复杂一点:

const transform = (objToTransform, filteringObj) => 
  applySpec(deepMap (compose (path, split('.'))) (filteringObj)) (objToTransform)

您可以编写自己的Ramda函数版本,即mostly easy。但是适用于嵌套属性的applySpec版本会更加困难。