【问题标题】:Modify values in an array of objects修改对象数组中的值
【发布时间】:2021-04-30 07:46:55
【问题描述】:

我有一个对象数组,我想使用另一个对象数组根据“类型”值修改它们。我得到了一大堆对象,但我应该只得到 2 个。

这就是我所拥有的:

const convertData = (type, value) => {
  switch (type) {
    case "date":
      {
        return new Date(Number(value)).toDateString();
      }
    case "currency":
      {
        return value ? `$${value}` : null;
      }
    default:
      return value;
  }
};

const headers = [{
  field: 'amount',
  type: 'currency'
}, {
  field: 'deliveredDate',
  type: 'date'
}]

const body = [{
  id: 1,
  amount: 4000,
  deliveredDate: "1610427600000"
}, {
  id: 2,
  amount: 6000,
  deliveredDate: "1611118800000"
}]

const result = body.map(i => {
  const keys = Object.keys(i);
  return keys.map(k => {
    return {
      ...i,
      [k]: headers.find(i => i.field === k) ? convertData(headers.find(i => i.field === k).type, i[k]) : null
    }
  })
})

console.log(result.flat())


/**
Expected Result
[{
  id: 1,
  amount: $4000,
  deliveredDate: "Tue Jan 12 2021"
}, {
  id: 2,
  amount: $6000,
  deliveredDate: "Wed Jan 20 2021"
}]
*/

headers 中的字段值表示 body 数组中的键。并且相应的body对象中的值需要根据header对象中的类型进行更改。请指教。

【问题讨论】:

  • 请不要这样 ping 用户。

标签: javascript arrays object mapping reduce


【解决方案1】:

一种可能的方法,它也允许灵活的适应和代码重用,利用经常被忽视的可选第二个参数,一个可以提供给大多数数组方法...thisArg for e.g. map

因此,这种方法确实会从 OP 的 headers 列表中创建一个 查找表,并将其提供给映射过程,因为人们不想搜索(在 @987654325 的每个迭代步骤中) @) 总是一次又一次地在同一个列表中找到正确/匹配的相关转换type

然后实际映射将很容易。实现一个函数,该函数假定其this 上下文是一个查找表,并通过查找正确的转换@(重新)创建提供的(此处当前处理的)对象的类型转换版本987654328@ 之前将其提供给 OP 的 convertData 函数。

const convertData = (type, value) => {
  switch (type) {
    case "date": {
      return new Date(Number(value)).toDateString();
    }
    case "currency": {
      return value ? `$${value}` : null;
    }
    default:
      return value;
  }
};

const headers = [{
  field: 'amount',
  type: 'currency'
}, {
  field: 'deliveredDate',
  type: 'date'
}];

const body = [{
  id: 1,
  amount: 4000,
  deliveredDate: "1610427600000"
}, {
  id: 2,
  amount: 6000,
  deliveredDate: "1611118800000"
}];

function createConversionTypeLookupTable(conversionTypeList) {
  return conversionTypeList.reduce((table, conversionTypeItem) => {

    table[conversionTypeItem.field] = conversionTypeItem.type;
    return table;

  }, {});
}

function createConvertedItemViaBoundLookupTable(item) {
  const lookupTable = (this || {}); // more fail safe.
  return Object.entries(item).reduce((obj, [key, value]) => {

    obj[key] = convertData((lookupTable[key] || key), value);
    return obj;

  }, {});
}

console.log(
  'Converted Item List ...',
  body.map(
    createConvertedItemViaBoundLookupTable,
    createConversionTypeLookupTable(headers)
  )
);
console.log(
  'Conversion Type Lookup Table ...',
  createConversionTypeLookupTable(headers)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

【讨论】:

  • @a2441918 ...对上述方法有任何疑问吗?
【解决方案2】:

JSON.stringify() 具有替换功能,可以满足 OP 的要求。

// OP code and data
//
const convertData = (type, value) => {
  switch (type) {
    case "date":
      {
        return new Date(Number(value)).toDateString();
      }
    case "currency":
      {
        return value ? `$${value}` : null;
      }
    default:
      return value;
  }
};

const headers = [{
  field: 'amount',
  type: 'currency'
}, {
  field: 'deliveredDate',
  type: 'date'
}]

const body = [{
  id: 1,
  amount: 4000,
  deliveredDate: "1610427600000"
}, {
  id: 2,
  amount: 6000,
  deliveredDate: "1611118800000"
}]

// use the OP code to convert a value to a string formatted by its key
//
const convertField = (key, value) => {
  let header = headers.find(e => e.field === key)
  return header ? convertData(header.type, value) : value
}

const convertedStr = JSON.stringify(body, convertField);
const convertedObj = JSON.parse(convertedStr);
console.log(convertedObj);

【讨论】:

  • 这种方法不仅由于完整的字符串化/解析周期而迭代 2 次,而且它还为每个单独的项目字符串化步骤一次又一次地迭代 headers 数组。它的使用也仅限于有效的 JSON 数据,并且不允许使用除此之外的其他数据结构。
  • @PeterSeliger,我认为你是对的:我的答案取决于有效的 JS 对象作为输入并以线性时间运行。如果您找到在亚线性时间内运行或处理格式错误的输入的解决方案,请告诉我。 ;-)
  • 1/2 有效的 JSON 数据和有效的 JS 对象是有区别的……并不是每一个完全有效的 JS 对象都可以直接映射成有效的 JSON 结构。您可能还会考虑JSON.stringifyJSON.parse 的实现;任何实现都会以某种方式在循环和/或递归中包含循环。使用前者肯定比精确迭代两次付出更大的代价......通过reduce创建一个数组以创建查找表,最后通过map创建原始数组。
  • 2/2 尽管 Q. 与性能无关,并且上述解决方案按预期工作,但我认为指出它的可能限制对 OP 会有所帮助(尤其是使用 @987654328 @ 而不是在每个转换器步骤中进行属性查找)。
【解决方案3】:

您调用 map 两次,一次是在数组上,一次是在键上,因此您得到的不仅仅是数组中的项目,而且对象不正确,因为您每次都在不同的对象上调用 convertData

考虑如下 -

const convertData = (type, value) => {
  switch (type) {
    case "date":
      {
        return new Date(Number(value)).toDateString();
      }
    case "currency":
      {
        return value ? `$${value}` : null;
      }
    default:
      return value;
  }
};

const headers = [{
  field: 'amount',
  type: 'currency'
}, {
  field: 'deliveredDate',
  type: 'date'
}]

const body = [{
  id: 1,
  amount: 4000,
  deliveredDate: "1610427600000"
}, {
  id: 2,
  amount: 6000,
  deliveredDate: "1611118800000"
}]

const result = body.map(i => {
  const newItem = {};
  for (const prop in i) {
    const header = headers.find(f => f.field === prop);
    const value = i[prop];
    newItem[prop] = header ? convertData(header.type, value) : value
  }
  return newItem;
});

console.log(result)

编辑 1:

const convertData = (type, value) => {
  switch (type) {
    case "date":
      {
        return new Date(Number(value)).toDateString();
      }
    case "currency":
      {
        return value ? `$${value}` : null;
      }
    default:
      return value;
  }
};

const headers = [{
  field: 'amount',
  type: 'currency'
}, {
  field: 'deliveredDate',
  type: 'date'
}]

const body = [{
  id: 1,
  amount: 4000,
  deliveredDate: "1610427600000"
}, {
  id: 2,
  amount: 6000,
  deliveredDate: "1611118800000"
}]

const result = body.map(i => {
  const newItem = {};
  var keys = Object.keys(i);
  keys.forEach((prop) => {
    const header = headers.find(f => f.field === prop);
    const value = i[prop];
    newItem[prop] = header ? convertData(header.type, value) : value
  });
  return newItem;
});

console.log(result);

【讨论】:

  • 谢谢@Nikhil。有没有办法不用 for of.. 我的 IDE 在使用保护时抛出错误。
  • @a2441918,更新答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-11
  • 1970-01-01
  • 2013-05-17
  • 2021-04-02
  • 2021-05-03
  • 1970-01-01
相关资源
最近更新 更多