Javascript:展平对象内的任何数组值(嵌套)

时间:2017-11-10 11:32:30

标签: javascript arrays recursion data-structures mapreduce

我想在对象中展平任何数组值,例如比如下面的sample。解决方案不应仅仅应用于ecommerce,而应该是对象中可能作为数组类型的任何内容。例如:

var sample = {
  price: "999",
  description: "...",
  ecommerce: {
    products: [
      {
        brand: "apple",
        category: "phone"
      },
      {
        brand: "google",
        category: "services"
      }
    ]
  }
};

我希望输出为:

{
  price: "999",
  description: "..."
  ecommerce: {
    products_1: {
      brand: "apple",
      category: "phone"
    },
    products_2: {
      brand: "google",
      category: "services"
    }
  }
}

在JavaScript(ES6 / 7)中执行此操作的最有效方法是什么?

提前致谢!

由于评论和一些缺点而更新!!!如果那些在最初被问到这个问题时如此快速点击弊端的人会撤销它会很好!

我已经尝试过这是完全错误的,我也确信这是一个更好的功能性方法:

function flattenArray(array) {

  var obj = array.reduce((acc, cur, i) => {
    acc[i] = cur;
    return acc;
  }, {});

  return obj;
}

function cleanObject(object) {
  for (let key in object) {
    let testObject = object[key];

    if (Array.isArray(testObject)) {
      testObject = flattenArray(testObject)
    } else if (typeof(testObject) === 'object') {
      testObject = cleanObject(testObject);
    }

    return testObject;
  }

  return object;
}

var clean = cleanObject(sample);

更新2:看到两个解决方案都在ecommerce上如此固定,如果下一个对象是,解决方案将如何工作:

var sample = {
  price: "999",
  description: "...",
  differentArray: [ 
    {
      brand: "apple",
      category: "phone"
    },
    {
      brand: "google",
      category: "services"
    }
  ]
};

请注意,这不同key不仅在不同的嵌套级别上也是如此。

3 个答案:

答案 0 :(得分:1)

基于递归应用的基于Array#reduce的方法可以完成这种键值包的工作......然后,第一个通用解决方案可能看起来像这个......

function recursivelyMapArrayItemsToGenericKeys(collector, key) {
  var
    source  = collector.source,
    target  = collector.target,
    type    = source[key];

  if (Array.isArray(type)) {
    type.forEach(function (item, idx) {
      var
        keyList     = Object.keys(item || ''),
        genericKey  = [key, idx].join('_');

      if (keyList.length >= 1) {
        target[genericKey] = keyList.reduce(recursivelyMapArrayItemsToGenericKeys, {

          source: item,
          target: {}

        }).target;
      } else {
        target[genericKey] = item;
      }
    });
  } else if (typeof type !== 'string') {
    var keyList = Object.keys(type || '');

    if (keyList.length >= 1) {
      target[key] = keyList.reduce(recursivelyMapArrayItemsToGenericKeys, {

        source: type,
        target: {}

      }).target;
    } else {
      target[key] = type;
    }
  } else {
    target[key] = type;
  }
  return collector;
}

var sample = {
  price: "999",
  description: "...",
  ecommerce: {
    products: [{
      brand: "apple",
      category: "phone"
    }, {
      brand: "google",
      category: "services"
    }, {
      foo: [{
        brand: "bar",
        category: "biz"
      }, {
        brand: "baz",
        category: "biz"
      }]
    }]
  }
};

var result = Object.keys(sample).reduce(recursivelyMapArrayItemsToGenericKeys, {

  source: sample,
  target: {}

}).target;

console.log('sample : ', sample);
console.log('result : ', result);
.as-console-wrapper { max-height: 100%!important; top: 0; }

...在下一个代码清理步骤中,可能会删除重复的逻辑,从而最终得到两个函数和一个交替/相互递归......

function recursivelyAssignItemsFromTypeByKeys(target, type, keyList, key) {
  if (keyList.length >= 1) {
    target[key] = keyList.reduce(recursivelyMapArrayItemsToGenericKeys, {

      source: type,
      target: {}

    }).target;
  } else {
    target[key] = type;
  }
}

function recursivelyMapArrayItemsToGenericKeys(collector, key) {
  var
    source  = collector.source,
    target  = collector.target,
    type    = source[key];

  if (Array.isArray(type)) {
    type.forEach(function (item, idx) {
      var
        keyList     = Object.keys(item || ''),
        genericKey  = [key, idx].join('_');

      recursivelyAssignItemsFromTypeByKeys(target, item, keyList, genericKey);
    });
  } else if (typeof type !== 'string') {
    var keyList = Object.keys(type || '');

    recursivelyAssignItemsFromTypeByKeys(target, type, keyList, key);
  } else {
    target[key] = type;
  }
  return collector;
}

var sample = {
  price: "999",
  description: "...",
  ecommerce: {
    products: [{
      brand: "apple",
      category: "phone"
    }, {
      brand: "google",
      category: "services"
    }, {
      foo: [{
        brand: "bar",
        category: "biz"
      }, {
        brand: "baz",
        category: "biz"
      }]
    }]
  }
};

var result = Object.keys(sample).reduce(recursivelyMapArrayItemsToGenericKeys, {

  source: sample,
  target: {}

}).target;

console.log('sample : ', sample);
console.log('result : ', result);
.as-console-wrapper { max-height: 100%!important; top: 0; }

答案 1 :(得分:0)

我要做什么:

const sample = {
  price: "999",
  description: "...",
  ecommerce: {
    products: [
      {
        brand: "apple",
        category: "phone"
      },
      {
        brand: "google",
        category: "services"
      }
    ]
  }
}

sample.ecommerce.products.forEach((p, i) => {
  sample.ecommerce['products_' + i] = p
})

delete sample.ecommerce.products

console.log(sample)

答案 2 :(得分:0)

只需reduce ecommerce数组并根据需要销毁每个元素。

const sample = {
  price: "999",
  description: "...",
  ecommerce: {
    products: [
      {
        brand: "apple",
        category: "phone"
      },
      {
        brand: "google",
        category: "services"
      }
    ]
  }
}

const flattenArray = (arr, key) =>
  arr.reduce((prev, curr, index) => {
    return {
      ...prev,
      [`${key}_${index + 1}`]: curr,
    }
  }, {})
  
const result = {
  ...sample,
  ecommerce: flattenArray(sample.ecommerce.products, 'products'),
}

console.log(result)