linq.js для группировки по массиву объектов в JavaScript
Я хочу использовать linq.js для группировки следующих данных по дате.
data2 = [{
"date": 1399298400.0,
"adId": 1057946139383,
"impressions": 1000000
}, {
"date": 1399298400.0,
"adId": 3301784671323,
"impressions": 535714
}...... etc.
];
Вот моя попытка:
var linq = Enumerable.From(data2);
data2 = linq.GroupBy(function (x) {
return x.date;
}).Select(function (x) {
return {
date: x.Key(),
impressions: x.Sum(function (y) {
return y.impressions | 0;
})
};
}).ToArray();
Тем не менее, это не работает правильно, потому что сумма всех impressions
до и после GroupBy
близки, но не идентичны.
Как правильно использовать group by в linq.js в этом случае?
Вот пример в скрипте с полным набором данных, который показывает общее количество показов до и после использования GroupBy
,
3 ответа
Для того, чтобы получить доступ к Key
собственностью GroupBy
Вы должны быть в группе по методу.
Вы можете сделать это, передав обратный вызов в качестве третьего параметра, например:
var aggregatedObject = Enumerable.From(dataArray)
.GroupBy("$.date", null,
function (key, g) {
return {
date: key,
impressions: g.Sum("$.impressions | 0")
}
})
.ToArray();
| 0
Часть уравнения - это способ очистки ваших данных. В приведенном ниже примере один из элементов массива данных случайно не обладает свойством впечатлений. Когда JavaScript суммирует все элементы в этой группе, он будет идти вперед, пока не встретит полностью отсутствующее значение, после чего результат всей агрегации будет ужасным NaN
:
Какая труба (|
Оператор) в JS возвращает первое значение, если оно существует, в противном случае возвращает второе. Таким образом, выражение защищает вас от недостающих свойств.
Рабочая демонстрация с помощью фрагментов стека:
var dataArray = [{
"date": 1396828800,
"impressions": 100
}, {
"date": 1396828800,
"impressions": 250
}, {
"date": 1397001600,
"impressions": 300
}, {
"date": 1397001600
//,"impressions": 450
}];
var aggregatedObject = Enumerable.From(dataArray)
.GroupBy("$.date", null,
function (key, g) {
return {
date: key,
impressions: g.Sum("$.impressions | 0")
}
})
.ToArray();
console.table(aggregatedObject);
<script src="//cdnjs.cloudflare.com/ajax/libs/linq.js/2.2.0.2/linq.min.js"></script>
Примечание: здесь используется сокращенный синтаксис, но если вы предпочитаете в любое время видеть строку со знаком доллара, вы можете заменить ее синтаксисом лямбда следующим образом (оба делают одно и то же):
// Lambda
.Select(function (x) { return x.impressions })
// Shorthand
.Select("$.impressions")
Кроме того, вы можете найти больше информации о группе linqjs по сумме
Я являюсь автором проекта с открытым исходным кодом http://www.jinqjs.com/. Вы можете легко сделать это в jinqJs следующим образом:
jinqJs().from(data2).groupBy('date').sum('impressions').select();
Дайте мне знать, если я могу быть больше помочь.
Вы можете попробовать сгруппировать по date.toString(). Может быть безопаснее из-за того, как JS оценивает равенство дат
В качестве альтернативы, люди, сталкивающиеся с этим вопросом, могут получить от нуля до большого количества покупок при использовании linq.js.
Если вы уже используете его, продолжайте, но если это первая пара реальных вариантов использования, стоит отметить, что вы можете сделать то же самое в vanilla js:
Для этих данных:
var dataArray = [
{ person: "james", likes: 100 },
{ person: "james", likes: 250 },
{ person: "kyle", likes: 300 },
{ person: "kyle" }
];
Вы можете построить объект со свойствами для каждого ключа / человека и продолжать суммировать значения этих реквизитов
var obj = dataArray.reduce((acc, cur) => {
acc[cur.person] = (acc[cur.person] || 0) + (cur.likes || 0)
return acc
}, {})
Если вы хотите, чтобы это был массив объектов, вы можете преобразовать объект в массив следующим образом
var array = Object.entries(obj).map(entry => {
return { person: entry[0], likes: entry[1] }
})