有没有简单的方法来回转换此JSON?

时间:2019-02-27 10:12:22

标签: javascript json postman

我们正在使用Postman进行API测试。我们返回的某些对象非常冗长且不易处理,因此我想创建一个辅助方法以使它们更加简洁。我知道有各种各样的转换库,例如node-json-transformselecttransformjsontransforms等,但是不幸的是,我只能使用Postman Sandbox libraries和普通JS。

我正在寻找最简单的方法(最少loc和函数)来转换此对象:

var verbose = [
    {
        "Key": "Name",
        "Value": "John Doe",
        "Instance": 1
    },
    {
        "Key": "Age",
        "Value": "33",
        "Instance": 1
    },
    {
        "Key": "Child",
        "Value": "Jane",
        "Instance": 1
    },
    {
        "Key": "Child",
        "Value": "Rocky",
        "Instance": 2
    }];

对此:

var concise =  {
    "Name": "John Doe",
    "Age": "33",
    "Child": ["Jane", "Rocky"]
};

,然后又回到详细形式。

我已经尝试了遍历每个对象并将属性/值添加到新对象的本机方法,但是当我到达多个实例键/值对时,这种方法很快就变得难看了。我可以想象有一种使用map / reduce的简便方法,但是我不熟悉那些方法。

6 个答案:

答案 0 :(得分:2)

根据我对您问题的理解,您想从verbose对象数组中创建键/值对。但是,如果存在键冲突,则应将值转换为数组。

考虑到这一点,您将必须:

  1. 使用forEach遍历对象数组。
  2. 如果键不冲突,我们只需创建一个新的键值对
  3. 如果按键发生冲突,则将变得有些棘手:
    • 如果键发生冲突且这是第一次发生,我们会将键值对中的值转换为数组
    • 如果键冲突并且这不是第一次发生,则表明我们正在查看数组
    • 现在我们肯定有一个数组,所以我们将值压入其中

请参见下面的概念验证:

var verbose = [{
    "Key": "Name",
    "Value": "John Doe",
    "Instance": 1
  },
  {
    "Key": "Age",
    "Value": "33",
    "Instance": 1
  },
  {
    "Key": "Child",
    "Value": "Jane",
    "Instance": 1
  },
  {
    "Key": "Child",
    "Value": "Rocky",
    "Instance": 2
  }];

var concise = {};
verbose.forEach(function(i) {
  var key = i['Key'];
  var value = i['Value'];
  
  // If item exists, we want to convert the value into an array of values
  if (key in concise) {
    var item = concise[key];
    
    // If it is not an array already, we convert it to an array
    if (!Array.isArray(item))
      item = [item];
      
    item.push(value);
    concise[key] = item;
  }
  
  // If item does not exist, we simply create a new key-value pair
  else {
    concise[key] = value;
  }
});
console.log(concise);

答案 1 :(得分:1)

您可以这样做:

const verbose = [{"Key": "Name","Value": "John Doe","Instance": 1},{"Key": "Age","Value": "33","Instance": 1},{"Key": "Child","Value": "Jane","Instance": 1},{"Key": "Child","Value": "Rocky","Instance": 2}];
const concise = Object.values(verbose.reduce((a, {Key, Value}) => (Key === 'Child' ? a.childs[0].Child.push(Value) : a.keys.push({[Key]: Value}), a), {keys: [], childs: [{Child: []}]})).flat(1);

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

答案 2 :(得分:1)

const verbose = [{
    "Key": "Name",
    "Value": "John Doe",
    "Instance": 1
  },
  {
    "Key": "Age",
    "Value": "33",
    "Instance": 1
  },
  {
    "Key": "Child",
    "Value": "Jane",
    "Instance": 1
  },
  {
    "Key": "Child",
    "Value": "Rocky",
    "Instance": 2
  }
];
let concise = {};

verbose.forEach(item => {
  const values = Object.values(item)
  if (concise[values[0]])  concise = {...concise, [values[0]]: [concise[values[0]], values[1]]};
  else concise = {...concise, ...{[values[0]]: values[1]}}
})

答案 3 :(得分:1)

尝试一下。我已经写了两个转换函数。 我看到其他答案仅提供了简洁明了的要求。

let verbose = [{
    "Key": "Name",
    "Value": "John Doe",
    "Instance": 1
  },
  {
    "Key": "Age",
    "Value": "33",
    "Instance": 1
  },
  {
    "Key": "Child",
    "Value": "Jane",
    "Instance": 1
  },
  {
    "Key": "Child",
    "Value": "Rocky",
    "Instance": 2
  }
]

let concise = {
  "Name": "John Doe",
  "Age": "33",
  "Child": ["Jane", "Rocky"]
}

verboseToConcise = (verbose) => {
  let obj = {}
  verbose.forEach(v => {
    let key = obj[v.Key]
    if (key) typeof key === 'string' ? obj[v.Key] = [key, v.Value] : key.push(v.Value)
    else obj[v.Key] = v.Value
  })
  return obj
}

conciseToVerbose = (concise) => {
  let arr = []
  Object.entries(concise).forEach(([key, value]) => {
    if (typeof value === 'object') {
      for (let i = 0; i < value.length; i++){
        arr.push({
          "Key": key,
          "Value": value[i],
          "Instance": i+1
        })
      }
    } else {
      arr.push({
        "Key": key,
        "Value": value,
        "Instance": 1
      })
    }
  })
  return arr
}

console.log(verboseToConcise(verbose))
console.log(conciseToVerbose(concise))

答案 4 :(得分:1)

在这里,我假设所有属性都是多值的,然后将长度为1的那些属性简化为简单值。这比反向方法要慢一些,在反向方法中,您假设值是单值的,并在证明相反的情况下将它们提升为数组,以遵守Instance施加的顺序。

function makeConcise(verbose) {
  let concise = {};
  verbose.forEach(({Key, Value, Instance}) => {
    if (!concise[Key]) concise[Key] = [];
    concise[Key][Instance - 1] = Value;
  });
  Object.keys(concise).forEach(Key => {
    if (concise[Key].length == 1) concise[Key] = concise[Key][0];
  });
  return concise;
}

反向功能同样简单:

function makeVerbose(concise) {
  let verbose = [];
  Object.keys(concise).forEach(Key => {
    if (Array.isArray(concise[Key])) {
      concise[Key].forEach((Value, index) => {
        verbose.push({Key, Value, Instance: index + 1});
      });
    } else {
      verbose.push({Key, Value: concise[Key], Instance: 1});
    }
  });
  return verbose;
}

答案 5 :(得分:1)

我也尝试使用reduce

编辑:不使用...扩展语法,而使用Object.assignarray.concat

EDIT2:我想尝试再次将其重新打开。在这段代码中,我们丢失了Instance:(

var verbose = [
  {
    Key: 'Name',
    Value: 'John Doe',
    Instance: 1,
  },
  {
    Key: 'Age',
    Value: '33',
    Instance: 1,
  },
  {
    Key: 'Child',
    Value: 'Jane',
    Instance: 1,
  },
  {
    Key: 'Child',
    Value: 'Rocky',
    Instance: 2,
  },
]

const concise = verbose.reduce(
  (p, n) =>
    Object.assign(p, {
      [n.Key]: !p.hasOwnProperty(n.Key)
        ? n.Value
        : typeof p[n.Key] === 'string'
        ? [p[n.Key], n.Value]
        : p[n.Key].concat(n.Value),
    }),
  {},
)

console.log(concise)
// { Name: 'John Doe', Age: '33', Child: [ 'Jane', 'Rocky' ] }

const backAgain = Object.entries(concise).reduce(
  (p, [k, v]) =>
    Array.isArray(v)
      ? p.concat(v.map(x => ({ Key: k, Value: x })))
      : p.concat({ Key: k, Value: v }),
  [],
)

console.log(backAgain)
// [ { Key: 'Name', Value: 'John Doe' },
//  { Key: 'Age', Value: '33' },
//  { Key: 'Child', Value: 'Jane' },
//  { Key: 'Child', Value: 'Rocky' } ]