将点符号字符串转换为对象和查找参考对象

问题描述 投票:2回答:3

我有一个点号表示的数组,例如:

var base = ['a.b.c','a.e','h'];

我也有一个参考对象:

var reference = { 
  a: { 
    b: { 
      c:"Hello", 
      d:"you" 
    }, 
    e:"beautiful",
    f:"and"
  },
  g:"kind",
  h:"World" 
};

我需要从基本符号字符串中构建一个对象,并从引用对象中获取值。不幸的是,我无法更改基准或参考。

我让它适用于数组的每个部分,但是问题是当我尝试合并对象时。它用a.e覆盖值a.b.c

我想要的输出是:

var desiredOutput = { 
  a: { 
    b: { 
      c:"Hello" 
    }, 
    e:"beautiful" 
  }, 
  h:"World" 
};

但是,下面的代码是我的输出:

var output = { 
    a: { 
        e: "beautiful" 
    },
    h: "World" 
};

任何帮助将不胜感激。我仅限于Object.assign。

function convert(base,reference) {
    var obj = {};

    var getObjectValue = function(string, reference) {
        var i = 0;
        while (reference && i < string.length) {
            reference = reference[string[i++]];
        }
        return reference;
    };

    for (var n = 0; n < base.length; n++) {    
        var s = base[n].split("."),
            x = obj;

        for(var i = 0; i < s.length-1; i++) {
            x = x[s[i]] = {}; 
        }

        x[s[i]] = getObjectValue(s,reference);
    }
    return obj;
}

var base = ['a.b.c','a.e','h'];

var reference = { 
  a: { 
    b: { 
      c:"Hello", 
      d:"you" 
    }, 
    e:"beautiful",
    f:"and"
  },
  g:"kind",
  h:"World" 
};

var desiredOutput = { 
  a: { 
    b: { 
      c:"Hello" 
    }, 
    e:"beautiful" 
  }, 
  h:"World" 
};

console.log(convert(base,reference));
javascript object append assign
3个回答
1
投票

与您一起

x = x[s[i]] = {}; 

即使已填充s[i]属性,您也将无条件覆盖它。仅在该属性尚不存在另一个对象的情况下,才分配一个新对象。

if (x[s[i]]) {
  x = x[s[i]];
} else {
  x = x[s[i]] = {};
}

function convert(base,reference) {
    var obj = {};

    var getObjectValue = function(string, reference) {
        var i = 0;
        while (reference && i < string.length) {
            reference = reference[string[i++]];
        }
        return reference;
    };

    for (var n = 0; n < base.length; n++) {    
        var s = base[n].split("."),
            x = obj;

        for(var i = 0; i < s.length-1; i++) {
            if (x[s[i]]) {
              x = x[s[i]];
            } else {
              x = x[s[i]] = {};
            }
        }

        x[s[i]] = getObjectValue(s,reference);
    }

    return obj;

}

var base = ['a.b.c','a.e','h'];

var reference = { 
  a: { 
    b: { 
      c:"Hello", 
      d:"you" 
    }, 
    e:"beautiful",
    f:"and"
  },
  g:"kind",
  h:"World" 
};

var desiredOutput = { 
  a: { 
    b: { 
      c:"Hello" 
    }, 
    e:"beautiful" 
  }, 
  h:"World" 
};


console.log(convert(base,reference));

这是我的处理方式:

var base = ['a.b.c','a.e','h'];
var reference = { 
  a: { 
    b: { 
      c:"Hello", 
      d:"you" 
    }, 
    e:"beautiful",
    f:"and"
  },
  g:"kind",
  h:"World" 
};

const results = {};
// Helper function to get the nested value from an array of properties:
const getVal = props => props.reduce((a, b) => a[b], reference);
for (const propStr of base) {
  // Turn string into an array of properties:
  const props = propStr.split('.');
  // Get nested value to assign at the end:
  const val = getVal(props);
  // Get last property to assign on the last object:
  const lastProp = props.pop();
  let obj = results;
  // Iterate through to the nested object on the `results`,
  // creating objects on the way only if they don't exist yet:
  while (props.length) {
    const prop = props.shift();
    if (obj[prop]) obj = obj[prop];
    else {
      obj[prop] = {};
      obj = obj[prop];
    }
  }
  obj[lastProp] = val;
}
console.log(results);

1
投票

这可以不使用while循环来实现!

我只使用了es6的Array.prototype.reduce(还有语义,但是您可以自己转换/转换它们)。您也可以轻松地对其进行多边形填充/填充,请参见this article

const base = ['a.b.c', 'a.e', 'h'];

const reference = { 
  a: { 
    b: { 
      c: 'Hello', 
      d: 'you' 
    }, 
    e: 'beautiful',
    f: 'and'
  },
  g: 'kind',
  h: 'World' 
};

const isObject = item => (item && typeof item === 'object' && !Array.isArray(item) && item !== null);

const pick = (obj, keys) => keys.split('.').reduce((prev, key) => {
  const ret = (prev || obj);
  if (isObject(ret) && key in ret) {
    return ret[key];
  }

  return prev;
}, null);

const extend = (target, source) => {
  if (isObject(target) && isObject(source)) {
    Object.keys(source).forEach((key) => {
      if (isObject(source[key])) {
        if (!target[key] || !isObject(target[key])) {
          target[key] = source[key];
        }
        extend(target[key], source[key]);
      } else {
        Object.assign(target, { [key]: source[key] });
      }
    });
  }
  return target || source;
};

const fromDotNotation = (dotNotation, value) => {
  const ret = {};
  dotNotation.split('.').reduce((prev, key, i, self) => {
    return prev[key] = (i === self.length - 1) ? value : prev[key] || {};
  }, ret);

  return ret;
}

const fromDotNotations = (source, dotNotations) => dotNotations.reduce((prev, dotNotation) => {
  return extend(prev, fromDotNotation(dotNotation, pick(source, dotNotation)));
}, {});

const output = fromDotNotations(reference, base);

console.log(JSON.stringify(output, null, 2));

在这里,我们希望能够以任何点表示法构建对象,并在其尾部添加初始值。我们将使用拔除方法从参考对象中选择初始值。遍历多个点符号,我们可以创建一个构造对象的数组。只需使用合并方法,我们就可以创建一个目标对象,我们要将构造的对象合并到其中。


1
投票

我创建了以下代码段,以使用嵌套的foreach的简单方式获得所需的结果,希望对您有所帮助。我在注释中描述了代码。

var reference = {
  a: {
    b: {
      c: "Hello",
      d: "you"
    },
    e: "beautiful",
    f: "and"
  },
  g: "kind",
  h: "World"
};

var base = ['a.b.c', 'a.e', 'h'];

var result = {};

base.forEach(str => {

  //split the base by `.`
  var arr = str.split('.');

  //get the value
  var val = arr.reduce((r, el) => r[el], reference);

  //set the initial temporary path of resulting object
  var tmp = result;

  arr.forEach((el, i) => {

    //set final property value into resulting object
    if (i == arr.length - 1)
      return tmp[el] = val;

    //create nested property in resulting object
    if (!tmp[el])
      tmp[el] = {};

    //update temporary path
    tmp = tmp[el];
  });
});

console.log(result)
© www.soinside.com 2019 - 2024. All rights reserved.