2016-01-21 4 views
0

У меня есть массив, содержащий отдельные массивы из 2 элементов, каждый из которых содержит дату в миллисекундах в первой ячейке и номер (номер транзакции) во 2-й ячейке. Это выглядит следующим образом:Группировка вложенных массивов с помощью первого элемента

var array = [[12135435123, -2], 
[12135435123, 1], 
[12135464565, -2], 
[12423675834, 0], 
[12423675834, 1]....]; 

Не все даты в мс одинаковы в каждой клетке, и я полностью составил даты выше, но логика та же.

Что я хочу сделать, это создать другой массив в той же структуре, что и выше (массивы из 2 элементов внутри глобального массива). Каждый элемент в глобальном массиве представляет собой 2-элементный массив, который представляет группу массивов с одинаковой датой, а именно: [transactionsCount, netTransaction].

transactionsCount - количество уникальных экземпляров даты или количество транзакций в уникальной дате. netTransaction - сумма вторых ячеек в этой группе или стоимость чистых транзакций для даты.

Используя приведенный выше пример, я хочу, чтобы окончательный массив выглядеть следующим образом:

var newArray = [[2, -1], [1,-2],[2,1]...]; 
// The first array is 2 and -1 because there are 2 transactions for the unique day and the -1 is the net transaction amount. The 2nd array is 1,-2 because there is only 1 transaction for the day with a net total of -2, etc, etc. 

То, что я сделал, было создать примитивную функцию, которая делает это для меня, но у меня есть проблемы, потому что есть случаи, когда функция перечитывает количество уникальных дней и выдает неправильные результаты. Так что я здесь делаю неправильно. Вот что у меня есть:

transactions = function transactions(array){ 
    var transactionCount = 0; 
    var netTransactionCounter = 0; 
    var finishedArray = []; 
    var tempDateArray = []; 

    array.forEach(function(item){ 
    var init = []; 
    if(tempDateArray.length == 0){ 
     tempDateArray.push(item[0]); 
     transactionCount++; 
     netTransactionCounter += Number(item[1]); 
    } else if(tempDateArray.length > 0){ 
     if(item[0] == tempDateArray[0]){ 
     transactionCount++; 
     netTransactionCounter += Number(item[1]); 
     } else if(item[0] !== tempDateArray[0]){ 
     tempDateArray.pop(); 
     tempDateArray.push(item[0]); 
     init.push(transactionCount); 
     init.push(netTransactionCounter); 
     finishedArray.push(init); 
     transactionCount = 1; 
     netTransactionCounter = Number(item[1]); 
     } 
    } 
    }); 

    return finishedArray; 

} 

Я действительно не люблю использовать forEach, но я в этом случае, потому что это менее грязный. Если кто-нибудь может мне помочь, я бы очень признателен.

ответ

1

Мне было сложно определить вашу логику, особенно с этим неопределенным массивом testing.

Я бы использовал логику словаря, чтобы собирать даты как уникальные ключи. Плюс это экономит усилия по управлению вычислениями длин (со всеми указанными вами счетчиками).

Я бы сказал, что следующий код является довольно понятным, но если у вас есть проблема с пониманием этого, не просите спросить.

var array = [[12135435123, -2], 
[12135435123, 1], 
[12135464565, -2], 
[12423675834, 0], 
[12423675834, 1]]; 

function transform (array) { 
var dictionary = {}; 
for (var i = 0 ; i < array.length ; i++){ 
    var date = array[i][0].toString(); 
    var value = array[i][1]; 

    // add the date to the dictionary if it's not already there 
    if ((date in dictionary) === false) 
    dictionary[date] = [0, 0]; 
    // update the count 
    dictionary[date][0]++; 
    // update the net sum 
    dictionary[date][1] += value;  
} 

// transform dictionary values to array 
var result = []; 
for (var key in dictionary) { 
    if (Object.prototype.hasOwnProperty.call(dictionary, key)) { 
     var val = dictionary[key]; 
     result.push(val); 
    } 
} 
return result; 
} 

alert(transform(array)); 

Вот JSFiddle.

+0

Извините за часть тестирования. Я забыл изменить его, потому что я изменил переменные перед публикацией здесь, чтобы иметь больше смысла, задавая вопрос. Спасибо за Ваш ответ. Я вернусь к вам как можно скорее. –

+0

Ваш метод намного более эстетичен и работает более плавно, чем то, что я делал выше. Спасибо за ваш ответ. –

1

Это использует ES6 для удобства, но может быть легко преобразован в ES5:

var array = [[12135435123, -2], 
[12135435123, 1], 
[12135464565, -2], 
[12423675834, 0], 
[12423675834, 1]]; 

//reduce the array into a map, creating objects using the date as keys - with the value being a hash of count and amount; 

var map = array.reduce((map, [date, amount]) => { 
    if (map[date]) { 
    map[date].count = map[date].count + 1; 
    map[date].amount = map[date].amount + amount; 
    } else { 
    map[date] = { count: 1, amount } 
    } 
    return map; 
}, {}); 

//Map over keys returning tuples of count and amount 
var newArray = Object.keys(map).map(key => [map[key].count, map[key].amount]) //gives the result you want; 

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

//reduce the array into a map, creating objects using the date as keys - with the value being a hash of count and amount; 

var map = array.reduce((map, [date, amount]) => { 
    var { count, net } = (map[date] || { count: 0, net : 0 }); 
    map[date] = { count: count + 1, net: net + amount }; 
    return map; 
}, {}); 

//Map over keys returning tuples of count and amount 
var newArray = Object.keys(map).map(key => [map[key].count, map[key].net]) //gives the result you want; 
Смежные вопросы