javascript 为每个分隔符将数组对象拆分为嵌套数组

tvokkenx  于 2023-05-27  发布在  Java
关注(0)|答案(4)|浏览(254)

我正在尝试拆分下面的数组

{
    "Base/Brand/0101-color-brand-primary-red": "#fe414d",
    "Base/Brand/0106-color-brand-secondary-green": "#00e6c3",
    "Base/Brand/0102-color-brand-primary-light-gray": "#eaecf0",
    "Base/Brand/0107-color-brand-secondary-black": "#000000",
    "Base/Brand/0103-color-brand-primary-white": "#ffffff",
    "Base/Brand/0108-color-brand-secondary-dark-gray": "#b4b4b4",
    "Base/Brand/0104-color-brand-secondary-blue": "#079fff",
    "Base/Light/Extended/Red/0201-color-extended-900-red": "#7f1d1d",
    "Base/Brand/0105-color-brand-secondary-yellow": "#ffe63b",
    "Base/Light/Extended/Red/0202-color-extended-800-red": "#991b1b"
}

这样的事情

{
  "Base": {
    "Brand": {
      "0101-color-brand-primary-red": "#fe414d",
      "0106-color-brand-secondary-green": "#00e6c3",
      "Light": {
        "Extended": {
          "Red": {
            "0201-color-extended-900-red": "#7f1d1d",
            "0202-color-extended-800-red": "#991b1b"
          }
        }
      }
    }
  }
}

基本上我需要分裂数组'/'和创建嵌套数组请帮助我如何才能实现这一点。

nsc4cvqm

nsc4cvqm1#

使用Object.entries获取原始对象中的所有条目。使用split('/')在输出中获取对象路径键的数组。然后在该路径数组上使用reduce在结果中创建级别,直到到达路径中的最后一个元素。此时,我们将最后一个路径元素设置为所需的颜色值。

const d = {
  "Base/Brand/0101-color-brand-primary-red": "#fe414d",
  "Base/Brand/0106-color-brand-secondary-green": "#00e6c3",
  "Base/Brand/0102-color-brand-primary-light-gray": "#eaecf0",
  "Base/Brand/0107-color-brand-secondary-black": "#000000",
  "Base/Brand/0103-color-brand-primary-white": "#ffffff",
  "Base/Brand/0108-color-brand-secondary-dark-gray": "#b4b4b4",
  "Base/Brand/0104-color-brand-secondary-blue": "#079fff",
  "Base/Light/Extended/Red/0201-color-extended-900-red": "#7f1d1d",
  "Base/Brand/0105-color-brand-secondary-yellow": "#ffe63b",
  "Base/Light/Extended/Red/0202-color-extended-800-red": "#991b1b"
}

const r = Object.entries(d).reduce((a, [p,v]) => 
  (p.split('/').reduce((a,c,i,r) => 
    a[c] ??= i<(r.length-1) ? {} : v, a), a), {})

console.log(r)
erhoui1w

erhoui1w2#

由于所提供的结构是键值对(条目)的平面(非嵌套)对象,因此可以通过reduce源对象的entries来开始聚合OP所需的目标数据结构。
这个外部reduce任务的 initial value 将是一个空对象(文字)。
同一个任务的 reducer函数 * 在每次迭代时都会接收到要聚合的对象引用(一开始就是初始值/空对象)。它还接收当前迭代的条目*,该条目是作为数组提供的 * 键值对 key实际上是key-path*,一个字符串,它可以在每一个出现的斜杠处进一步是splitvalue是***路径值***,必须作为任何聚合(部分)对象引用的最后一个值分配。
因此,需要第二个嵌套的reduce任务来处理每个键路径的部分key值。initial value 将始终是要聚合的对象的基或根引用。内部的reduce任务通过either accessing an already existing node, or by creating a new (empty node) or by assigning将接收到的node引用聚合到最后创建的节点的最终路径值。它也总是将这个引用作为当前节点传递到下一个迭代步骤。

const sampleData = {
  "Base/Brand/0101-color-brand-primary-red": "#fe414d",
  "Base/Brand/0106-color-brand-secondary-green": "#00e6c3",
  "Base/Brand/0102-color-brand-primary-light-gray": "#eaecf0",
  "Base/Brand/0107-color-brand-secondary-black": "#000000",
  "Base/Brand/0103-color-brand-primary-white": "#ffffff",
  "Base/Brand/0108-color-brand-secondary-dark-gray": "#b4b4b4",
  "Base/Brand/0104-color-brand-secondary-blue": "#079fff",
  "Base/Light/Extended/Red/0201-color-extended-900-red": "#7f1d1d",
  "Base/Brand/0105-color-brand-secondary-yellow": "#ffe63b",
  "Base/Light/Extended/Red/0202-color-extended-800-red": "#991b1b",
};

function createObjectFromKeyPartialsAndValues(data) {
  return Object
    .entries(data)
    .reduce((root, [keyPath, pathValue]) => {

      keyPath
        .split('/')
        .reduce((node, key, idx, keyList) => {

          const isLastKey = !keyList.hasOwnProperty(idx + 1);
          const value = isLastKey ? pathValue : {};

          const obj = (node[key] ??= value);
          return obj;

        }, root);

      return root;

    }, {});
}

console.log(
  createObjectFromKeyPartialsAndValues(sampleData)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
3yhwsihp

3yhwsihp3#

首先,在未来,请分享你自己的努力时,问一个问题。我不会回答,直到我看到你自己的方法,如果没有已经体面的答案在这里。
我手边有许多实用函数。其中之一是hydrate,它接受一个我称之为pathEntries的数组(类似于Object .entries的结果,但使用字符串/整数的 * 数组 * 表示 * 路径 *,而不是属性的单个字符串)并返回一个对象。有了这些,我们可以编写一个非常简单的版本:

const expand = (o) =>
  hydrate (Object .entries (o) .map (([k, v]) => [k.split('/'), v]))

hydrate基于setPath,它创建了一个对象的副本(尽可能多地共享),在给定的路径上有一个新的值,在此过程中创建新的节点。
比如说

setPath 
  (['foo', 'bar', 0, 'baz']) 
  (42) 
  ({foo: {qux: {corge: 100, grault: 99}}, waldo: 0})
//=> {foo: {bar: [{baz: 42}], qux: {corge: 100, grault: 99}}, waldo: 0}

综合起来,我的解决方案看起来像这样:

const setPath = ([p, ...ps]) => (v) => (o) =>
  p == undefined ? v : Object .assign (
    Array .isArray (o) || Number .isInteger (p) ? [] : {},
    {...o, [p]: setPath (ps) (v) ((o || {}) [p])}
  )

const hydrate = (xs) =>
  xs .reduce ((a, [p, v]) => setPath (p) (v) (a), {})

const expand = (o) =>
  hydrate (Object .entries (o) .map (([k, v]) => [k.split('/'), v]))

const flatData = {"Base/Brand/0101-color-brand-primary-red": "#fe414d", "Base/Brand/0106-color-brand-secondary-green": "#00e6c3", "Base/Brand/0102-color-brand-primary-light-gray": "#eaecf0", "Base/Brand/0107-color-brand-secondary-black": "#000000", "Base/Brand/0103-color-brand-primary-white": "#ffffff", "Base/Brand/0108-color-brand-secondary-dark-gray": "#b4b4b4", "Base/Brand/0104-color-brand-secondary-blue": "#079fff", "Base/Light/Extended/Red/0201-color-extended-900-red": "#7f1d1d", "Base/Brand/0105-color-brand-secondary-yellow": "#ffe63b", "Base/Light/Extended/Red/0202-color-extended-800-red": "#991b1b"}

console .log (expand (flatData))
.as-console-wrapper {max-height: 100% !important; top: 0}
mzsu5hc0

mzsu5hc04#

你可以用下面的递归函数来实现。它所做的是用“/”分割每个路径,然后以递归的方式检查它们,并将每个部分添加到输出对象中,如果它们还没有被追加。

const list = {
  "Base/Brand/0101-color-brand-primary-red": "#fe414d",
  "Base/Brand/0106-color-brand-secondary-green": "#00e6c3",
  "Base/Brand/0102-color-brand-primary-light-gray": "#eaecf0",
  "Base/Brand/0107-color-brand-secondary-black": "#000000",
  "Base/Brand/0103-color-brand-primary-white": "#ffffff",
  "Base/Brand/0108-color-brand-secondary-dark-gray": "#b4b4b4",
  "Base/Brand/0104-color-brand-secondary-blue": "#079fff",
  "Base/Light/Extended/Red/0201-color-extended-900-red": "#7f1d1d",
  "Base/Brand/0105-color-brand-secondary-yellow": "#ffe63b",
  "Base/Light/Extended/Red/0202-color-extended-800-red": "#991b1b",
};

const result = {};

Object.entries(list).forEach((entry) => {
  const path = entry[0]; // "Base/Brand/0101-color-brand-primary-red"
  const value = entry[1]; // "#fe414d"
  sections = path.split("/"); // ["Base", "Brand", "0101-color-brand-primary-red"]

  // start creating the output object using a recursive function
  sett(result, sections, sections[0], 0, sections.length, value);
});

function sett(parentObj, sections, currentSection, currentIndex, depth, value) {
  // stop if we've reached the end of the path
  if (currentIndex >= depth) return;

  // if not, check if this is the last section of the path
  const isLastSection = sections[currentIndex + 1] === undefined;

  // if there is not already an entry in result for this section (e.g  "Base" or "brand")
  if (!parentObj[currentSection])
    // if it's the end of the path (e.g one of the colors like 0101-color-brand-primary-red) assign it the value else assign {} to it
    parentObj[currentSection] = isLastSection ? value : {};

  // else go deeper in the path
  const nextSection = sections[currentIndex + 1];

  sett(
    parentObj[currentSection],
    sections,
    nextSection,
    currentIndex + 1,
    depth,
    value
  );
}

console.log(result);

相关问题