首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >比较两个嵌套的数据结构,target+source,与它们的源对应值相比,丢失目标值的适当合并策略是什么?

比较两个嵌套的数据结构,target+source,与它们的源对应值相比,丢失目标值的适当合并策略是什么?
EN

Stack Overflow用户
提问于 2022-05-18 08:57:34
回答 2查看 126关注 0票数 0

什么是更好的方法来做这件事。我将两个属性值(来自两个不同的对象)中的任何一个(取决于它们的存在)分配给第三种数据结构。

如果args对象的值为无主,则从default对象访问非空值并分配给最终结构。

代码语言:javascript
运行
复制
return {
  first: {
    visible: args.first?.visible ?? defaulttest.first?.visible,
    emoji: args.first?.emoji ?? defaulttest.first?.emoji,
    style: args.first?.style ?? defaulttest.first?.style,
  },
  back: {
    visible: args.back?.visible ?? defaulttest.back?.visible,
    emoji: args.back?.emoji ?? defaulttest.back?.emoji,
    style: args.back?.style ?? defaulttest.back?.style,
  },
  page: {
    visible: args.page?.visible ?? defaulttest.page?.visible,
    emoji: args.page?.emoji ?? defaulttest.page?.emoji,
    style: args.page?.style ?? defaulttest.page?.style,
  },
  forward: {
    visible: args.forward?.visible ?? defaulttest.forward?.visible,
    emoji: args.forward?.emoji ?? defaulttest.forward?.emoji,
    style: args.forward?.style ?? defaulttest.forward?.style,
  },

  last: {
    visible: args.last?.visible ?? defaulttest.last?.visible,
    emoji: args.last?.emoji ?? defaulttest.last?.emoji,
    style: args.last?.style ?? defaulttest.last?.style,
  },
  Mdelete: {
    visible: args.Mdelete?.visible ?? defaulttest.Mdelete?.visible,
    emoji: args.Mdelete?.emoji ?? defaulttest.Mdelete?.emoji,
    style: args.Mdelete?.style ?? defaulttest.Mdelete?.style,
  },
  removeBtn: {
    visible: args.removeBtn?.visible ?? defaulttest.removeBtn?.visible,
    emoji: args.removeBtn?.emoji ?? defaulttest.removeBtn?.emoji,
    style: args.removeBtn?.style ?? defaulttest.removeBtn?.style,
  },
};
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-05-18 12:58:41

从我上面的评论..。

1/2。实际上,OP并不是真的比较。对于某一组属性,OP查找每个属性的目标对象,并且只有在它具有一个空值的情况下,才会将源对象的对应项分配给缺少的属性。所以我选择的方法是. 2/2 .实现一个泛型函数,该函数合并两个对象,只有在目标结构尚未提供非空值的情况下,才能写入/分配源属性。然后,必须对argsdefaulttest调用两次该函数,第二次调用将返回完全为空的数据结构和args

上述声明有点野心勃勃,因为至少有两种策略说明了如何实现这样的合并。

因此,下面提供的示例代码实现了两种方法

  • 一种是refit,它遵循推送/修补的议程,因为它迫使源对象中的所有非无效财产分配给目标对象的非无效对象。
  • 第二种方法叫做revive,它类似于一种拉力方法,因为它只是重新分配空的目标对象属性和它们的非空源对象对应物。

他们为一个和相同的预设所产生的结果的差异将由她来证明。

代码语言:javascript
运行
复制
// "refit" ... a pushing/patching approach.
// - force the assignement of every non nullish property in source
//   to its non nullish counterpart in target ... hence a *refit*.
function refitNullishValuesRecursively(target, source) {
  if (
    // are both values array-types?
    Array.isArray(source) &&
    Array.isArray(target)
  ) {
    source
      // for patching always iterate the source items ...
      .forEach((sourceItem, idx) => {
        // ... and look whether a target counterpart exists.
        if (target[idx] == null) {

          // either assign an existing structured clone ...
          if (sourceItem != null) {
            target[idx] = cloneDataStructure(sourceItem);
          }
        } else {
          // ... or proceed recursively.
          refitNullishValuesRecursively(target[idx], sourceItem);
        }
      });
  } else if (
    // are both values object-types?
    source && target &&
    'object' === typeof source &&
    'object' === typeof target
  ) {
    Object
      // for patching ...
      .entries(source)
      // ... always iterate the source entries (key value pairs) ...
      .forEach(([key, sourceValue], idx) => {
        // ... and look whether a target counterpart exists.
        if (target[key] == null) {

          // either assign an existing structured clone ...
          if (sourceValue != null) {
            target[key] = cloneDataStructure(sourceValue);
          }
        } else {
          // ... or proceed recursively.
          refitNullishValuesRecursively(target[key], sourceValue);
        }
      });
  }
  return target;
}
// "revive" ... a pulling approach.
// - just reassign the nullish target properties with their
//   non nullish source counterparts ... hence a *revive*.
function reviveNullishValuesRecursively(target, source) {
  if (
    // are both values array-types?
    Array.isArray(target) &&
    Array.isArray(source)
  ) {
    target
      // for fixing always iterate the target items.
      .forEach((targetItem, idx) => {
        if (targetItem == null) {

          // either assign an existing structured clone ...
          target[idx] = cloneDataStructure(source[idx]) ?? targetItem;
        } else {
          // ... or proceed recursively.
          reviveNullishValuesRecursively(targetItem, source[idx]);
        }
      });
  } else if (
    // are both values object-types?
    target && source &&
    'object' === typeof target &&
    'object' === typeof source
  ) {
    Object
      // for fixing ...
      .entries(target)
      // ... always iterate the target entries (key value pairs).
      .forEach(([key, targetValue], idx) => {
        if (targetValue == null) {

          // either assign an existing structured clone ...
          target[key] = cloneDataStructure(source[key]) ?? targetValue;
        } else {
          // ... or proceed recursively.
          reviveNullishValuesRecursively(targetValue, source[key]);
        }
      });
  }
  return target;
}
const cloneDataStructure =
  ('function' === typeof structuredClone)
  && structuredClone
  || (value => JSON.parse(JSON.stringify(value)));

const targetBlueprint = {
  x: { xFoo: 'foo', xBar: 'bar', xBaz: { xBiz: null } },
  y: { yFoo: 'foo', yBar: null },
};
const patch = {
  x: { xFoo: null, xBar: null, xBaz: { xBiz: 'biz' } },
  y: { yFoo: null, yBar: 'bar', yBaz: { yBiz: 'biz' } },
};
let target = cloneDataStructure(targetBlueprint);

console.log('"refit" ... a pushing/patching approach.');
console.log('before refit ...', { target, patch });
refitNullishValuesRecursively(target, patch);
console.log('after refit ...', { target, patch });

target = cloneDataStructure(targetBlueprint);

console.log('"revive" ... a pulling approach.');
console.log('before revive ...', { target, patch });
reviveNullishValuesRecursively(target, patch);
console.log('after revive ...', { target, patch });
代码语言:javascript
运行
复制
.as-console-wrapper { min-height: 100%!important; top: 0; }

至于面向创建某种配置对象的OP示例,您可以完全修补/重构临时或当前args-config的一个克隆,而在最后一步中,您可以通过提供最基本的空配置库来控制配置对象的最终结构,而之前创建的完整修补程序/refit config只会恢复该配置库。

代码语言:javascript
运行
复制
function refitNullishValuesRecursively(target, source) {
  if (Array.isArray(source) && Array.isArray(target)) {
    source
      .forEach((sourceItem, idx) => {
        if (target[idx] == null) {

          if (sourceItem != null) {
            target[idx] = cloneDataStructure(sourceItem);
          }
        } else {
          refitNullishValuesRecursively(target[idx], sourceItem);
        }
      });
  } else if (
    source && target &&
    'object' === typeof source &&
    'object' === typeof target
  ) {
    Object
      .entries(source)
      .forEach(([key, sourceValue], idx) => {
        if (target[key] == null) {

          if (sourceValue != null) {
            target[key] = cloneDataStructure(sourceValue);
          }
        } else {
          refitNullishValuesRecursively(target[key], sourceValue);
        }
      });
  }
  return target;
}
function reviveNullishValuesRecursively(target, source) {
  if (Array.isArray(target) && Array.isArray(source)) {
    target
      .forEach((targetItem, idx) => {
        if (targetItem == null) {

          target[idx] = cloneDataStructure(source[idx]) ?? targetItem;
        } else {
          reviveNullishValuesRecursively(targetItem, source[idx]);
        }
      });
  } else if (
    target && source &&
    'object' === typeof target &&
    'object' === typeof source
  ) {
    Object
      .entries(target)
      .forEach(([key, targetValue], idx) => {
        if (targetValue == null) {

          target[key] = cloneDataStructure(source[key]) ?? targetValue;
        } else {
          reviveNullishValuesRecursively(targetValue, source[key]);
        }
      });
  }
  return target;
}
const cloneDataStructure =
  ('function' === typeof structuredClone)
  && structuredClone
  || (value => JSON.parse(JSON.stringify(value)));

const defaultConfig = {
  first: {
    visible: 'default.first.visible',
    emoji: 'default.first.emoji',
    style: 'default.first.style',
  },
  forward: {
    visible: 'default.forward.visible',
    emoji: 'default.forward.emoji',
    style: 'default.forward.style',
  },
  removeBtn: {
    visible: 'default.removeBtn.visible',
    emoji: 'default.removeBtn.emoji',
    style: 'default.removeBtn.style',
  },
};
const currentConfig = {
  first: {
    visible: 'current.first.visible',
    emoji: 'current.first.emoji',
    style: 'current.first.style',
  },
  forward: {
    visible: 'current.forward.visible',
    emoji: null,
  },
  FOO: {
    visible: 'current.FOO.visible',
    emoji: 'current.FOO.emoji',
    style: 'current.FOO.style',
  }
};

function getConfiguration(baseConfig) {
  return reviveNullishValuesRecursively(
    cloneDataStructure(baseConfig),
    refitNullishValuesRecursively(
      cloneDataStructure(currentConfig),
      defaultConfig,
    ),
  );
}
console.log(
  getConfiguration({
    first: null,
    forward: null,
    removeBtn: null,
  })
);
代码语言:javascript
运行
复制
.as-console-wrapper { min-height: 100%!important; top: 0; }

票数 0
EN

Stack Overflow用户

发布于 2022-05-18 10:21:19

如果您的对象的结构是您所呈现的结构,您可以:

代码语言:javascript
运行
复制
function normalize(input, defaultValue) {
    // Loop on the outer keys
    Object.keys(input).forEach(mainKey => {
        // Loop on the inner keys
        Object.keys(input[mainKey]).forEach(key => {
            // set the value of the key as itself or default if null
            input[mainKey][key] = input[mainKey]?.[key] ?? defaultValue[mainKey]?.[key]
        })
    })
    return input;
}

调用normalize(args, defaulttest),您将在每个内部键上循环,检查它是否存在,如果不存在,则在相同的路径中用默认值替换它。

示例:

代码语言:javascript
运行
复制
const x = {
  a: {a1: '1', a2: '2'},
  b: {b1: '1', b2: null}
}

const y = {b: {b2: '5'}}

console.log(normalize(x,y))

输出:

代码语言:javascript
运行
复制
{
    "a": {
        "a1": "1",
        "a2": "2"
    },
    "b": {
        "b1": "1",
        "b2": "5"
    }
}

使用这种方法,您必须在args输入中有键。如果缺少该键,则它将不会被默认替换。要使它工作,即使不存在的键,您需要使用第三种结构与所有可能的路径,例如。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72286105

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档