2016-08-04 5 views
1

У меня есть два массива, один из которых представляет данные, а другой - интервалы. Оба сортируются, и их начальные и конечные значения совпадают. Я просматриваю вложенные для циклов вычисления среднего значения точек данных за данный интервал. В результате я получаю одно значение данных для каждого интервала. Для массивов меньшего размера, < 100-500 длины, эти линейные петли выполняют свою работу, однако этот подход становится проблемой с несколькими тысячами точек данных. Любые рекомендации будут оценены.Массивы JavaScript - эффективно вычислять среднее значение в заданных интервалах

Пожалуйста, смотрите упрощенный код ниже со ссылкой на JSfiddle в конце

var TimelineArray = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100], 
 
\t DataArray = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100], 
 
\t DataArrayA = []; 
 

 
for (i = 0; i < TimelineArray.length-1; i++) { 
 
\t var dataPointsInGivenTimeInterval = []; 
 
\t for (j = 0; j < DataArray.length; j++) { 
 
\t \t if (DataArray[j] > TimelineArray[i] && DataArray[j] <= TimelineArray[i+1]) { 
 
\t \t \t dataPointsInGivenTimeInterval.push(DataArray[j]); 
 
\t \t } 
 
\t }; 
 
\t if (dataPointsInGivenTimeInterval.length == 0) { 
 
\t \t DataArrayA.push(null); 
 
\t } 
 
\t else { 
 
\t \t var sumOfdataPoints = null; 
 
\t \t for (k = 0; k < dataPointsInGivenTimeInterval.length; k++) { 
 
\t \t \t sumOfdataPoints += dataPointsInGivenTimeInterval[k]; 
 
\t \t } 
 
\t \t var avg = sumOfdataPoints/dataPointsInGivenTimeInterval.length; 
 
\t \t DataArrayA.push(avg); 
 
\t } 
 
} // end for 
 

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

Выход консоли

[0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100] 
[4.75, 15, 25.25, 36, null, 56.2, 64, 75, 89, 95] 

Вот код на JSfiddle - calculating average values for given intervals

+0

У меня есть простое решение для получения средних значений из массивов, если это помогает? и сложный, который добавляет такие функции к математическому объекту? – SpYk3HH

+0

https://github.com/JDMcKinstry/Math.Extensions использовать 'Math.average ([0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100])' приводит к '49.09090909090909' – SpYk3HH

+0

Является ли TimelineArray всегда одинаковым интервалом между элементами (в данном случае 10)? – 10100111001

ответ

2

Поскольку массивы сортируются, вы можете сделать это линейно относительно размера шкалы времени и данных:

var timeline = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100], 
 
    data = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100]; 
 
var averages = new Array(timeline.length - 1); 
 
for (var i = 0, j = 0; i < timeline.length; i++) { 
 
    var sum = 0, 
 
     items = 0; 
 
    for (; data[j] <= timeline[i]; j++) { 
 
    sum += data[j]; 
 
    ++items; 
 
    } 
 
    if(i) averages[i-1] = sum/items; 
 
} 
 
console.log(averages);
.as-console-wrapper { 
 
    max-height: 100% !important; 
 
    top: 0; 
 
}

0

Не уверен, если это будет быстрее, но вот трещина на него по-другому:

var TimelineArray = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100], 
 
DataArray = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100], 
 
DataArrayA = []; 
 
    
 
function avg(arr){ 
 
    if(arr!= null && arr.length > 0) 
 
    return arr.reduce(function(a, b){ return a+b;}, 0)/arr.length; 
 
    return null; 
 
} 
 
for(var i = 0; i < TimelineArray.length-1; i++){ 
 
    var interval = [TimelineArray[i], TimelineArray[i+1]]; 
 
    var data = DataArray.filter(function(a){ return a > interval[0] && a <= interval[1]}); 
 
    DataArrayA.push(avg(data)); 
 
} 
 

 
console.log(DataArrayA);

эд он 1: удалил петлю.

1

Вам не нужно повторно сканировать DataArray с самого начала на каждой итерации.

var TimelineArray = [0, 10, 20, 30, 40, 40, 60, 70, 80, 90, 100]; 
 
var DataArray = [0, 2, 4, 5, 8, 11, 19, 22, 24, 25, 30, 31, 38, 39, 51, 56, 57, 58, 59, 64, 74, 76, 89, 91, 92, 94, 98, 100]; 
 

 
var res = [], pos = 0; 
 

 
TimelineArray.forEach(function(v, i) { 
 
    for(var sum = 0, n = 0; DataArray[pos] <= v; n++) { 
 
    sum += DataArray[pos++]; 
 
    } 
 
    i && res.push(n ? sum/n : null); 
 
}); 
 

 
console.log(res);

+0

Мне нравится идея не сканировать весь массив данных с самого начала на каждой итерации. Как насчет конечной части? Я считаю, что та же идея может быть применена к концевому тегу того же массива данных. Как только значение данных станет больше правого края данного интервала в цикле, тогда очевидно, что остальная часть массива данных будет больше. Поэтому их тоже можно игнорировать. – user2217057

+0

Обратите внимание, что @Oriol избил меня на 10 минут с помощью очень похожего решения, которое также не перепрограммируется с самого начала. ^^ Не уверен, что понял вашу идею в конце. Это не относится к вашему набору данных примера, поскольку оба массива заканчиваются на уровне 100, не так ли? – Arnauld

+0

ОК, на самом деле это уже есть, я просто пропустил его, в коде @ Oriol условие вложенного цикла делает то, что я упоминал (; data [j] <= timeline [i]; j ++). Ваш код делает то же самое. Большое спасибо! – user2217057

Смежные вопросы