【问题标题】:Array of Objects: Create new object for each specified key that has a value对象数组:为每个具有值的指定键创建新对象
【发布时间】:2018-04-13 23:16:21
【问题描述】:

我有一个从 CSV 文件中提取的对象数组,如下所示:

    const data = [
  { name: 'p1', 'date started': 'April 2007', Houston: '375', Dallas: '508', Austin: '', 'El Paso': '1232' },
  { name: 'p2', 'date started': 'April 2017', Houston: '', Dallas: '', Austin: '', 'El Paso': '43' },
  { name: 'p3', 'date started': 'June 2012', Houston: '18789', Dallas: '', Austin: '8977', 'El Paso': '6754656' },
  { name: 'p4', 'date started': 'December 2015', Houston: '878', Dallas: '4556', Austin: '987', 'El Paso': '1456232' }
]

我正在创建一些数据的图表和表格,并且需要创建两个新键,'location'和'value',并为每个对象中的每个位置值创建新对象,如下所示:

    const newData = [
  { location: 'Houston', value: '375', name: 'p1', 'date started': 'April 2007' },
  { location: 'Dallas', value: '508', name: 'p1', 'date started': 'April 2007' },
  { location: 'El Paso', value: '1232', name: 'p1', 'date started': 'April 2007' },
  { location: 'El Paso', value: '43', name: 'p2', 'date started': 'April 2017' },
  { location: 'Houston', value: '18789', name: 'p3', 'date started': 'June 2012' },
  { location: 'Austin', value: '8977', name: 'p3', 'date started': 'June 2012' },
  { location: 'El Paso', value: '6754656', name: 'p3', 'date started': 'June 2012' },
  { location: 'Houston', value: '878', name: 'p4', 'date started': 'December 2015' },
  { location: 'Dallas', value: '4556', name: 'p4', 'date started': 'December 2015' },
  { location: 'Austin', value: '987', name: 'p4', 'date started': 'December 2015' },
  { location: 'El Paso', value: '1456232', name: 'p4', 'date started': 'December 2015' }
]

我之前必须为一个类似的项目执行此操作,时间紧迫,最终手动编辑了原始 CSV 文件。我宁愿不再那样做。到目前为止,我已经尝试了 map/forEach 和 Object.keys 的各种组合,但没有成功。

任何想法将不胜感激!

【问题讨论】:

    标签: javascript arrays object foreach


    【解决方案1】:

    您可以迭代对象的所有键并排除不需要的属性并为结果集构建新对象。

    var data = [{ name: 'p1', 'date started': 'April 2007', Houston: '375', Dallas: '508', Austin: '', 'El Paso': '1232' }, { name: 'p2', 'date started': 'April 2017', Houston: '', Dallas: '', Austin: '', 'El Paso': '43' }, { name: 'p3', 'date started': 'June 2012', Houston: '18789', Dallas: '', Austin: '8977', 'El Paso': '6754656' }, { name: 'p4', 'date started': 'December 2015', Houston: '878', Dallas: '4556', Austin: '987', 'El Paso': '1456232' }],
        result = data.reduce(function (r, o) {
            Object.keys(o).forEach(function (k)  {
                if (['name', 'date started'].includes(k) || !o[k]) {
                    return;
                }
                r.push({ location: k, value: o[k], name: o.name, 'date started': o['date started'] });
            });
            return r;
        }, []);
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

    • 这太聪明了,效果很好,而且会为我节省大量时间!谢谢一百万!
    • @JoshuaSwiss:在现实生活中,不要使用逻辑运算符来代替流控制。你会受到需要阅读你代码的人的强烈反对。一个更明智的解决方案如下所示:jsfiddle.net/5fvLc8mm 它使用适当的流控制,避免重复分配排除键数组,并避免在o[k] 为真时从该数组中查找。当代码布局合理时,这些东西更容易发现。
    【解决方案2】:

    您可以遍历所有 items 这是您的旧对象,然后遍历旧对象中的所有键并基于它构建一个新数组,就像这样

    const data = [
            { name: 'p1', 'date started': 'April 2007', Houston: '375', Dallas: '508', Austin: '', 'El Paso': '1232' },
            { name: 'p2', 'date started': 'April 2017', Houston: '', Dallas: '', Austin: '', 'El Paso': '43' },
            { name: 'p3', 'date started': 'June 2012', Houston: '18789', Dallas: '', Austin: '8977', 'El Paso': '6754656' },
            { name: 'p4', 'date started': 'December 2015', Houston: '878', Dallas: '4556', Austin: '987', 'El Paso': '1456232' }
        ];
    
    function transform() {
        
        var newObjects = [];
        data.forEach(item => {
            Object.keys(item).forEach(keyName => {
                if (keyName !== "name" && keyName !== "date started") {
                    newObjects.push({
                        location: keyName,
                        value: item[keyName],
                        ["date started"]: item["date started"],
                        name: item["name"]
                    })
                }
            });
        });
        return newObjects;
    }
    
    console.log(transform(data));

    希望对你有帮助

    【讨论】:

      【解决方案3】:

      使用解构赋值和 rest/spread 语法,这变得非常干净。

      const data = [
        { name: 'p1', 'date started': 'April 2007', Houston: '375', Dallas: '508', Austin: '', 'El Paso': '1232' },
        { name: 'p2', 'date started': 'April 2017', Houston: '', Dallas: '', Austin: '', 'El Paso': '43' },
        { name: 'p3', 'date started': 'June 2012', Houston: '18789', Dallas: '', Austin: '8977', 'El Paso': '6754656' },
        { name: 'p4', 'date started': 'December 2015', Houston: '878', Dallas: '4556', Austin: '987', 'El Paso': '1456232' }
      ];
      
      const result = data.reduce((res, obj) => {
        const date_started = obj["date started"];
        delete obj["date started"];
        const {name, ...rest} = obj;
        
        return [...res, ...Object.entries(rest).map(([k,v]) =>
          ({location:k, value:v, name:name, 'date started':date_started})
        )]
      }, []);
      
      console.log(result);

      如果您希望避免对象字面量中的 rest 参数,并且您不想要空位置,您可以创建一个 Set 用于排除非位置键,并使用真值评估来排除不受欢迎的位置。

      var data = [{ name: 'p1', 'date started': 'April 2007', Houston: '375', Dallas: '508', Austin: '', 'El Paso': '1232' }, { name: 'p2', 'date started': 'April 2017', Houston: '', Dallas: '', Austin: '', 'El Paso': '43' }, { name: 'p3', 'date started': 'June 2012', Houston: '18789', Dallas: '', Austin: '8977', 'El Paso': '6754656' }, { name: 'p4', 'date started': 'December 2015', Houston: '878', Dallas: '4556', Austin: '987', 'El Paso': '1456232' }];
      
      var exc = new Set(['name', 'date started']);
      var result = data.reduce((r, o) =>
          [
            ...r, 
            ...Object.entries(o)
              .filter(([k, v]) => v && !exc.has(k))
              .map(([k, v]) => ({ location: k, value: v, name: o.name, 'date started': o['date started'] }))
          ]
      , []);
      
      console.log(result, null, 2);

      【讨论】:

      • 用对象休息。
      • @NinaScholz:它只会在尚未实现该功能的浏览器中失败。你不知道这个功能吗?
      • @NinaScholz 去哪儿了?
      • 我知道这个功能,但还没有实现。
      • @NinaScholz:没有任何功能总是被实现。这就是我们有转译器的原因。
      【解决方案4】:

      使用完全通用的方法,OP 可以控制必须为每个新创建的数据项“按原样”分配的所有键值对……甚至是每个数据输入元组的代理键...

      var data = [
        { name: 'p1', 'date started': 'April 2007', Houston: '375', Dallas: '508', Austin: '', 'El Paso': '1232' },
        { name: 'p2', 'date started': 'April 2017', Houston: '', Dallas: '', Austin: '', 'El Paso': '43' },
        { name: 'p3', 'date started': 'June 2012', Houston: '18789', Dallas: '', Austin: '8977', 'El Paso': '6754656' },
        { name: 'p4', 'date started': 'December 2015', Houston: '878', Dallas: '4556', Austin: '987', 'El Paso': '1456232' }
      ];
      
      var newData = data.reduce(function (collector, dataItem) {
        var
        //itemEntryList = Object.entries(dataItem); // if available, otherwise next line ...
          itemEntryList = Object.keys(dataItem).map(function (key) {
            return [key, dataItem[key]];
          }),
          assignerList = [],
          assignerKey,
          idx = -1,
          keyForDataKey = collector.keyForDataKey,
          keyForDataValue = collector.keyForDataValue,
          protectedKeyList = collector.protectedKeyList;
      
        // implement a local `reject` ... for all key value pairs that have to be copied "as is".
        while ((assignerKey = itemEntryList[++idx]) && (assignerKey = assignerKey[0])) {
          if (protectedKeyList.some(function (protectedKey) {
            return (assignerKey === protectedKey);
          })) {
            assignerList.push({ key: assignerKey, value: itemEntryList[idx][1] });
            itemEntryList.splice(idx, 1);
            --idx;
          }
        }
        // create new data-item base-structures from the remaining `dataItem` tuples after the `reject` step.
        var dataItemList = itemEntryList.reduce(function (itemList, dataTuple) {
      
          var tupleValue = dataTuple[1];
          if (tupleValue) {
            var newDataItem = {};
            newDataItem[keyForDataKey] = dataTuple[0];
            newDataItem[keyForDataValue] = tupleValue;
      
            itemList.push(newDataItem);
          //itemList.push({ location: dataTuple[0], value: tupleValue });
          }
          return itemList;
      
        }, []);
      
        // for each new data item ...
        dataItemList.map(function (newDataItem) {
          return assignerList.reduce(function (dataItem, assignerItem) {
      
            // ... reassign all formerly rejected key value pairs that have to be copied "as is".
            dataItem[assignerItem.key] = assignerItem.value;
            return dataItem;
      
          }, newDataItem)
        });
      
        // collect all new data items.
        collector.dataItemList = collector.dataItemList.concat(dataItemList);
      
        return collector;
      
      }, {
      
        keyForDataKey:    'location',
        keyForDataValue:  'value',
      
        protectedKeyList: ['name', 'date started'],
        dataItemList:     []
      
      }).dataItemList;
      
      
      console.log('data : ', data);
      console.log('newData : ', newData);
      .as-console-wrapper { max-height: 100%!important; top: 0; }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-01-08
        • 2017-02-07
        • 1970-01-01
        • 1970-01-01
        • 2020-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多