如何在JavaScript中将对象的值与公共密钥组合?

时间:2017-11-16 16:08:50

标签: javascript json highcharts underscore.js

我正在尝试根据其中一个键合并JSON数组中的一些项目。我希望按“度量”进行分组,然后我需要查看“rounded_counts”中的所有时间/值数据,如果时间相同,则需要将值相加。这是源数据:

let sourceData = [
  {
    "metric": "Approved",
    "rounded_counts": [
      { "2017-11-16 15:10:00": 3 }, 
      { "2017-11-16 15:11:00": 5 }
    ]
  },
  {
    "metric": "Approved",
    "rounded_counts": [
      { "2017-11-16 15:10:00": 28 },
      { "2017-11-16 15:11:00": 28 }
    ]
  },
  {
    "metric": "Quarantine",
    "rounded_counts": [
      { "2017-11-16 15:10:00": 1 },
      { "2017-11-16 15:11:00": 2 }
    ]
  }
];

以下是Highcharts图表库所需的输出 - 请注意名为“已批准”的2个指标如何合并其值

可以使用下划线和/或ES6 - 提前致谢!

let chartData = [
  {
    "name": "Approved",
    "data": [
      [ "2017-11-16 15:10:00", 30 ],
      [ "2017-11-16 15:11:00", 33 ]
    ]
  },
  {
    "name": "Quarantine",
    "data": [
      [ "2017-11-16 15:10:00", 1 ],
      [ "2017-11-16 15:11:00", 2 ]
    ]
  }
]

5 个答案:

答案 0 :(得分:2)

这是我的两分钱。

const sourceData = [
  {
    "metric": "Approved",
    "rounded_counts": [
      { "2017-11-16 15:10:00": 3 },
      { "2017-11-16 15:11:00": 5 }
    ]
  },

  {
    "metric": "Approved",
    "rounded_counts": [
      { "2017-11-16 15:10:00": 28 },
      { "2017-11-16 15:11:00": 28 }
    ]
  },

  {
    "metric": "Quarantine",
    "rounded_counts": [
      { "2017-11-16 15:10:00": 1 },
      { "2017-11-16 15:11:00": 2 }
    ]
  }
];

function mergeDatas(currentObject, rounded_counts) {
  return rounded_counts.map(x => {
    if (currentObject.data.some(y => y[0] === Object.keys(x)[0])) {
      const miniArray = currentObject.data.find(y =>
      y[0] === Object.keys(x)[0]);

      miniArray[1] += x[Object.keys(x)[0]];

      return miniArray;
    }

    return x;
  })
}

const result = sourceData.reduce((tmp, x) => {
  if (tmp.some(t => t.name === x.metric)) {
    const currentObject = tmp.find(y => y.name === x.metric);

    mergeDatas(currentObject, x.rounded_counts);

    return tmp;
  }

  tmp.push({
    name: x.metric,
    data: x.rounded_counts.map(y => {
      const key = Object.keys(y)[0];

      return [key, y[key]];
    }),
  });

  return tmp;
}, []);

console.log(result);

答案 1 :(得分:1)

看看这样的事情:

[{
      "metric": "Approved",
        "rounded_counts": [
          { "2017-11-16 15:10:00": 3 },
          { "2017-11-16 15:11:00": 5 }
        ]
    },
    ...
].reduce((tmp, x) => {
  const ptr = tmp;

  // look if it exist
  const index = ptr.findIndex(y => y.name === x.metric);

  // It exist
  if (index !== -1) {
    ptr[index].data = addSimilarDatesValues([
      ...ptr[index].data,
      ...x.rounded_counts,
    ]);

    return ptr;
  }

  // it doesn't
  ptr.push({
    name: x.metric,
    data: x.rounded_counts.map(y => [
        Object.keys(y)[0],
        y[Object.keys(y)[0]],
    ]),
  });

  return ptr;
}, []);
/**
 * We have this in entry
 *
 * [
 *   { "2017-11-16 15:10:00": 3 }, 
 *   { "2017-11-16 15:11:00": 5 },
 *   { "2017-11-16 15:10:00": 28 },
 *   { "2017-11-16 15:11:00": 28 },
 * ]
 *
 * Or this
 *
 * [
 *   [ "2017-11-16 15:10:00", 3 ], 
 *   [ "2017-11-16 15:11:00", 5 ],
 * ]
 *
 *
 * WARNING: Here you can have already converted data
 * It happens when we push the first item into the list
 *
 * We return this
 *
 * [
 *   [ "2017-11-16 15:10:00", 31 ], 
 *   [ "2017-11-16 15:11:00", 33 ],
 * ]
 * 
 */
const addSimilarDatesValues = (array) => {
  return array.reduce((tmp, x) => {
    const ptr = tmp;

    // Handle the already converted data
    const isArray = x instanceof Array;

    const keyToStore = isArray ? x[0] : Object.keys(x)[0];
    const valueToStore = isArray ? x[1] : x[Object.keys(x)[0]];

    // Look if there is a date already in tmp
    const index = ptr.findIndex(y => y[0] === keyToStore);

    // It's not
    if (index === -1) {
      // add a new entry for the date
      return [
        ...ptr,
        [
          keyToStore,
          valueToStore,
        ],
      ];
    }

    // It is - add the value into the already stored one
    ptr[index][1] += valueToStore;

    return ptr;
  }, []);
};

const addSimilarDatesValues = (array) => {
  return array.reduce((tmp, x) => {
    const ptr = tmp;
    const isArray = x instanceof Array;

    const keyToStore = isArray ? x[0] : Object.keys(x)[0];
    const valueToStore = isArray ? x[1] : x[Object.keys(x)[0]];

    // Look if there is a date already in tmp
    const index = ptr.findIndex(y => y[0] === keyToStore);

    // It's not
    if (index === -1) {
      // add a new entry for the date
      return [
        ...ptr, [
          keyToStore,
          valueToStore,
        ],
      ];
    }

    // It is - add the value into the already stored one
    ptr[index][1] += valueToStore;

    return ptr;
  }, []);
};

const ret = [{
    "metric": "Approved",
    "rounded_counts": [{
        "2017-11-16 15:10:00": 3
      },
      {
        "2017-11-16 15:11:00": 5
      },
    ]
  },
  {
    "metric": "Approved",
    "rounded_counts": [{
        "2017-11-16 15:10:00": 28
      },
      {
        "2017-11-16 15:11:00": 28
      },
    ]
  },
  {
    "metric": "Quarantine",
    "rounded_counts": [{
        "2017-11-16 15:10:00": 1
      },
      {
        "2017-11-16 15:11:00": 2
      },
    ]
  }
].reduce((tmp, x) => {
  const ptr = tmp;

  // look if it exist
  const index = ptr.findIndex(y => y.name === x.metric);

  // It exist
  if (index !== -1) {
    ptr[index].data = addSimilarDatesValues([
      ...ptr[index].data,
      ...x.rounded_counts,
    ]);

    return ptr;
  }

  // it doesn't
  ptr.push({
    name: x.metric,
    data: x.rounded_counts.map(y => [
      Object.keys(y)[0],
      y[Object.keys(y)[0]],
    ]),
  });

  return ptr;
}, []);

console.log(ret);

答案 2 :(得分:0)

尽管@Grégory的答案相当优雅,但它并没有输出正确的表格。 function包含一个键/值对象,而不是包含1个键和1个值的2个元素的数组。

请改为尝试:

data

答案 3 :(得分:0)

由于数据结构的原因,您似乎需要使用一些嵌套循环和比较。我不认为你可以用javascript中的内置数组函数来做到这一点。试试这个:

    let sourceData = [{
      "metric": "Approved",
      "rounded_counts": [{
        "2017-11-16 15:10:00": 3
      }, {
        "2017-11-16 15:11:00": 5
      }]
    }, {
      "metric": "Approved",
      "rounded_counts": [{
        "2017-11-16 15:10:00": 28
      }, {
        "2017-11-16 15:11:00": 28
      }]
    }, {
      "metric": "Quarantine",
      "rounded_counts": [{
        "2017-11-16 15:10:00": 1
      }, {
        "2017-11-16 15:11:00": 2
      }]
    }];
    let chartData = [];

    function isSame(obj1, obj2) {
      if (obj1.metric && obj1.metric == obj2.metric &&
         obj1.rounded_counts && obj2.rounded_counts &&
         obj1.rounded_counts.length == obj2.rounded_counts.length) {
        var roundedCountsDifferent = false;
        for (var i in obj1.rounded_counts) {
          var count = 0;
          var key1;
          var key2;
          for (var j in obj1.rounded_counts[i]) {
            key1 = j;
            break;
          }
          for (var j in obj2.rounded_counts[i]) {
            key2 = j;
            break;
          }
          roundedCountsDifferent = key1 != key2;
          return !roundedCountsDifferent;
        }
      }
      return false;
    }
    for (var i in sourceData) {
      var source = sourceData[i];
      var existingChart = null;
      for (var j in chartData) {
        if (isSame(source, chartData[j])) {
          existingChart = chartData[j];
          for (var k in source.rounded_counts) {
            var key;
            var val;
            for (var kv in source.rounded_counts[k]) {
              val = source.rounded_counts[k][kv];
              break;
            }
            for (var kv in existingChart.rounded_counts[k]) {
              existingChart.rounded_counts[k][kv] += val;
              break;
            }
          }
        }
      }
      if (!existingChart) {
        chartData.push(source);
      }
    }
    console.log(chartData);

工作小提琴: https://jsfiddle.net/h1n70m7s/1/

答案 4 :(得分:-1)

我认为这就是你要找的东西。这是合并两个数据集,添加第一个不存在的第二个项目的值。

有很多评论,因此您可以在处理数据时跟进。



let sourceData = [
    {
        "metric": "Approved",
        "rounded_counts": [
            { "2017-11-16 15:10:00": 3 }, 
            { "2017-11-16 15:11:00": 5 }
        ]
    },
    {
        "metric": "Approved",
        "rounded_counts": [
            { "2017-11-16 15:10:00": 28 },
            { "2017-11-16 15:11:00": 28 },
            { "2017-11-16 15:12:00": 29 }
        ]
    },
    {
        "metric": "Quarantine",
        "rounded_counts": [
            { "2017-11-16 15:10:00": 1 },
            { "2017-11-16 15:11:00": 2 }
        ]
    }
];

let chartData = []; // our combined output Dataset

// map over the sourceData one item at a time. 
sourceData.map((item) => {
    let d = chartData.find(data => data.metric == item.metric);
    if ( d ) { // if an existing item exists
        //console.log("item exists"); console.log(d);

        // create a new array of the existing items
        rounded_counts = d.rounded_counts;

        // iterate all the rounded_counts in the current item
        item.rounded_counts.map((count) => {

            let key = Object.keys(count)[0]; // get the key for the current object, this would be the datetime
            // console.log("key: " + key);

            // check for any existing items with the same key (datetime)
            let additional = rounded_counts.find(data => Object.keys(data)[0] == key);
            // console.log(additional); // print the additional item raw

            if (additional) {
                // console.log(additional[Object.keys(additional)]); // print the additional items value, this is the value we will add to the existing item with the same "metric" and same value
                let Z = (count[key] + additional[Object.keys(additional)]); // add our 2 values together
                // console.log(Z);  // print this new value
                let newObj = {}; newObj[key] = Z; // create a new Object with the new value and existing key
                rounded_counts[rounded_counts.findIndex(data => Object.keys(data)[0] == key)] = newObj; // update the existing rounded_count item with our new object
            } else {
                rounded_counts.push(count);
            }
        });

        // set the exists items rounded_counts to our new array
        d.rounded_counts = rounded_counts;

    } else {
        chartData.push(item);
    }
});

// print the dataset so we can inspect the results
console.log(chartData);