用新值连接对象并将其转换为数组

时间:2019-04-29 07:59:17

标签: javascript arrays typescript object ecmascript-6

我有这样的情况:我正在努力反对新的key-value对,例如:

let a1 = {key1: 'val1'};
let a2 = {key2: 'val2'};
const result = {...a1, ...a2};

结果是我得到一个有效的新对象:{key1: 'val1', key2: 'val2'}

但是有第三种情况:

let a1 = {key1: 'val1'};
let a2 = {key2: 'val2'};
let b1 = {key1: 'val1b'};
const result = {...a1, ...a2, ...b1};

因此我应该得到:

{key1: ['val1', 'var1b'], key2: 'val2'}`.

所以->如果已经有这样的键->将此键值转换为数组并将其推入。

我尝试过:

用于...我要推送的所有对象:

const keysToPush = Object.keys(b1);
const keysInitial = Object.keys(a1); // foreach too
if (keysInitial.includes(keysToPush)) // push as array

但是看起来很丑

也许应该有更优雅的解决方案?

4 个答案:

答案 0 :(得分:1)

您需要查看每个属性,并确定是分配还是转换为数组并推入值。

const
    migrate = (target, source) => {
        Object.keys(source).forEach(key => {
            if ([].concat(target[key] || []).includes(source[key])) return;
            if (key in target) {
                if (!Array.isArray(target[key])) target[key] = [target[key]];
                target[key].push(source[key]);
            } else {
                target[key] = source[key];
            }
        });
        return target;
    };

var a1 = { key1: 'val1' },
    a2 = { key2: 'val2' },
    b1 = { key1: 'val1b' },
    b2 = { key1: 'val1b' },
    result = [a1, a2, b1, b2].reduce(migrate, {});

console.log(result);

答案 1 :(得分:1)

检查密钥是否存在。如果是这样,请检查它是否为数组,并相应地处理每种情况:

let a1 = {
  key1: 'val1'
};
let a2 = {
  key2: 'val2'
};
let b1 = {
  key1: 'val1b'
};

const merge = (...o) => {
  let res = o.reduce((acc, curr) => {
    Object.entries(curr).forEach(([k, v]) => {
      acc[k] = (acc[k] && Array.isArray(acc[k]) ? [...acc[k], v] : (acc[k] ? [acc[k], v] : v));
    });
    return acc;
  });
  return res;
};

let result = merge(a1, a2, b1);
console.log(result);
.as-console-wrapper {
  max-height: 100% !important;
  top: auto;
}

答案 2 :(得分:1)

我建议使用Map(用于键)({每个键的值)Set(用于键),因为Set将确保没有重复的值。在过程结束时,Map可以转换为普通对象,Set可以转换为单个值或值数组:

// Sample input with some repetition:
const objects = [
    { key1: 'val1' },
    { key2: 'val2' },
    { key1: 'val1b' },
    { key2: 'val2' },
    { key1: 'val1b' }
];

const pairs = objects.flatMap(Object.entries);
const map = new Map(pairs.map(([k]) => [k, new Set]));
pairs.forEach(([k, v]) => map.get(k).add(v));
const result = Object.fromEntries(Array.from(map, ([k, set]) => 
   set.size < 2 ? [k, ...set] : [k, [...set]]
));

console.log(result);

答案 3 :(得分:0)

您可以创建一个合并对象的函数。解决步骤为:

  • 创建一个使用rest参数接受任意数量对象的函数
  • 创建一个将成为结果的空对象。
  • 使用forEach遍历所有对象。在forEach内创建另一个嵌套的forEach,以遍历对象的条目。
  • 检查键是否已存在于结果obj中。

    • 检查其值是否为数组,然后向其推送新值。

    • 如果不是数组,只需将其转换为两个值的数组

  • 如果键不存在,则通常将其添加为对象的键。

function mergeObjs(...objs){
  const res = {};
  objs.forEach(x => {
    Object.entries(x).forEach(([k,v]) => {
      if(res[k]){
        if(Array.isArray(res[k])) res[k].push(v)
        else res[k] = [res[k],v]
      }
      else res[k] = v;
    })
  })
  return res;
}

let a1 = {key1: 'val1'};
let a2 = {key2: 'val2'};
let b1 = {key1: 'val1b'};

console.log(mergeObjs(a1,a2,b1))