优化CSV数据上的javascript循环

时间:2017-06-17 21:08:40

标签: javascript arrays csv d3.js

我正在使用d3.js绘制图表,方法是加载外部.CSV文件。 我到目前为止的代码使用少量数据工作正常,但是当我加载一个包含数千行的较大文件时,它会杀死页面。

数据的使用列是一整天每30分钟一次的值,将持续数月。

请参阅Plunker示例。

var avgClientArr = [];
var dateArr = [];
var dateGroupArr = [];

function csvParseClient() {
    d3.xhr('client.csv').get(function(err, response) {
        var dirtyCSV = response.responseText;
        var initialClientKeys = /TYPE,DATE,START TIME,END TIME,USAGE,UNITS,NOTES/i;
        var newClientKeys = "TYPE,x,startTime,endTime,y,UNITS,NOTES";
        var csvDataClient = dirtyCSV.replace(initialClientKeys, newClientKeys);
        var validData = csvDataClient.substr(csvDataClient.indexOf(newClientKeys));
        var csvData = d3.csv.parse(validData);

        csvData.customForEach(function(val, i) {
            // filter data
            //var keep = ['x', 'startTime', 'endTime', 'UNITS', 'y'];
            //for (var key in val[i]) {
            //    if (keep.indexOf(key) === -1) {
            //        delete val[i][key];
            //    }
            //}

            // parse data
            var date = val.x;
            var usage = val.y;
            var startTime = val.startTime;
            var endTime = val.endTime;
            var x = new Date(date);
            var y = parseFloat(usage);

            dateArr.push({
                "date": x,
                "usage": y
            })
            dateGroupArr = groupBy(dateArr, 'date');
        })
console.log(dateGroupArr);
        var objDates = objectValues(dateGroupArr);

        objDates.customForEach(function(f) {
                var avg = f.reduce(function(a, b) {
                    return a + b.usage;
                }, 0) / f.length;
                var date = f.reduce(function(a, b) {
                    return new Date(b.date);
                }, 0);
                avgClientArr.push({
                    "x": date,
                    "y": avg
                })
            })
            //console.log("avgClientArr", avgClientArr);
        document.getElementById('arrayDiv').innerHTML = '<pre>' + JSON.stringify(avgClientArr, null, 4) + '</pre>';
    })
}

function groupBy(arr, key) {
    var reducer = (grouped, item) => {
        var group_value = item[key]
        if (!grouped[group_value]) {
            grouped[group_value] = []
        }
        grouped[group_value].push(item)
        return grouped
    }
    return arr.reduce(reducer, {})
}

function objectValues(object) {
    var values = []
    for (var property in object) {
        if (object.hasOwnProperty(property)) {
            values.push(object[property])
        }
    }
    return values
}

function foreach(fn) {
    var arr = this;
    var len = arr.length;
    for (var i = 0; i < len; ++i) {
        fn(arr[i], i);
    }
}

Object.defineProperty(Array.prototype, 'customForEach', {
    enumerable: false,
    value: foreach
});

var t0 = performance.now();
csvParseClient();
var t1 = performance.now();
console.log("Call csvParseClient() " + (t1 - t0) + " milliseconds.");

我需要做什么

我需要将整天返回的平均使用值设为y,并将当天的日期返回为x每天。

我有一个缓慢的过程

  1. 从CSV文件中的指定行开始循环,因为前几行有不需要的数据。
  2. 将唯一日期分组并将该日期的每个使用值存储在对象中。
  3. 平均每个日期的使用价值。
  4. 输出一个对象数组,其中属性x为日期,y为平均使用价值。
  5. 如果你可以给我任何关于如何让这个跑得更快的帮助,那就太好了!

1 个答案:

答案 0 :(得分:0)

我通过使用d3 nest()rollup()函数解决了这个问题,它简单且非常快。

d3.nest()
.key(function(d) {
    return d.x;
})
.rollup(function(d) {
    var avg = d3.mean(d, function(g) {return g.y; });
    return avg;
}).entries(dateArr);