Агрегирование значений объектов массивов JavaScript? - PullRequest
4 голосов
/ 17 июня 2011

В JavaScript задано n чисел в качестве входных данных в этом формате: (n = 2)

array1:
[{x: 1, y: 5},{x: 2, y: 3},{x: 3, y: 6}]

array2:
[{x: 1, y: 2},{x: 2, y: 6},{x: 3, y: 2}]

Как мне легко собрать значения Y и получить полученный массив:

arrayOutput:
[{x: 1, y: 7},{x: 2, y: 9},{x: 3, y: 8}]

Спасибо.

Ответы [ 2 ]

3 голосов
/ 17 июня 2011

Обновление : дополнительный комментарий о значениях x и их положениях в массивах делает приведенное ниже неактуальным.

Никакого особенного трюка нет, вы просто просматриваете массивы и получаете результат. Это не что иное, как вложенный цикл. Если вы пытаетесь быть максимально эффективными в широком диапазоне движков JavaScript, избегайте ненужных вызовов функций.

Что-то в соответствии с:

function sumYValues(arrays) {
    var outer, inner, array, entry, sum, result, x;

    // Create our result array with a copy of the first array
    result = [];
    if (arrays.length > 0) {
        array = arrays[0];
        for (inner = 0; inner < array.length; ++inner) {
            entry = array[inner];
            result[inner] = {x: entry.x, y: entry.y};
        }

        // Add in the remaining values
        for (outer = 1; outer < arrays.length; ++outer) {
            array = arrays[outer];
            // You might want an assert here verifying that result.length == array.length
            for (inner = 0; inner < array.length; ++inner) {
                entry = array[inner];
                // You might want an assert here verifying that result[inner].x == entry.x
                result[inner].y += entry.y;
            }
        }
    }

    return result;
}

Эти циклы считаются от 0 (или 1) до array.length - 1. Вы можете указать, является ли обратный ход (array.length - 1 к 0 (или 1)) более быстрым, в основном "вниз до 0". Раньше я предполагал, что это было потому, что это было в C, когда я был молодым человеком (сравнения с 0 быстрее, чем сравнения с другой переменной), но это предположение может или не может быть допустимым в JavaScript.


Конкретных ярлыков нет, вы просто просматриваете массивы, сравниваете их и получаете результат.

Если значения x будут уникальными в каждом массиве, может быть проще отслеживать текущую сумму, используя объект, а не массив и используя значения x в качестве ключей, а затем преобразовав их в массив, когда вы закончите. E.g.:

function sumYValues(arrays) {
    var outer, inner, ar, entry, sum, result, x;

    sum = {};
    for (outer = 0; outer < arrays.length; ++outer) {
        ar = arrays[outer];
        for (inner = 0; inner < arrays.length; ++inner) {
            entry = ar[inner];
            sum[entry.x] = (sum[entry.x] || 0) + entry.y;
        }
    }

    result = [];
    for (x in sum) {
        result.push({x: x, y: sum[x]});
    }

    return result;
}

Вышеприведенное описание в основном просто для демонстрации использования sum, объекта, в качестве карты значений x => y, хотя в нем также реализована хотя бы некоторая логика суммирования.

Эта строка может нуждаться в пояснении:

            sum[entry.x] = (sum[entry.x] || 0) + entry.y;

Если sum не имеет записи для этого значения x, sum[entry.x] будет undefined, что является значением "falsey". Поэтому мы используем необычайно мощный || оператор , чтобы либо получить значение для этого x из sum или 0, а затем добавить * 1050 текущей записи * к нему и сохраните результат.

3 голосов
/ 17 июня 2011

Бенчмарк Пример

Обратите внимание, что смешанный код быстрее, за ним следуют циклы, за которыми следует нативный / подчеркивание.

function createOutput(arr1, arr2, arr3 /*, ... */) {
    return Array.prototype.reduce.call(arguments, function (prev, curr) {
        return prev.map(function(val, index) {
            return {
                x: val.x,
                y: val.y + curr[index].y
            }
        });
    });
}

Предполагается массивысортируются и содержат все значения x в порядке 1..n без пропусков.

Вид требует ES5.Это может быть заменено на _, который дает такую ​​функциональность в кросс-браузерной манере.

С подчеркиванием это

function createOutput() {
    return _.reduce(arguments, function (memo, arr) {
        return _.map(memo, function(val, index) {
            return { x: val.x, y: val.y + arr[index].y };
        });
    });
}
...