[英]Javascript Equivalent to C# LINQ GroupBy
這是以下問題的后續問題:
我們正在使用 Angular 2 + TypeScript:
我有一個對象數組。 數組中的每個 object 都包含一個名為“StudentType”的屬性。
我需要運行 C# LINQ 樣式查詢,提取數組中的 StudentType 列表和具有該特定類型的數組成員數。
雖然我可以做一個老式循環並執行此操作,但我想知道是否有更好的方法來執行此操作,例如 C# LINQ GroupBy 提供的方法。
由於我們使用的是Angular 2,項目負責人不允許使用JQuery。
我剛剛編寫了一些用於測試的 studentType 值,但您可以使用Array.prototype.reduce()迭代輸入數組的每個元素並添加或操作累加器對象的屬性。
let arr = [{ studentType: 'freshman' }, { studentType: 'senior' }, { studentType: 'sophomore' }, { studentType: 'freshman' }, { studentType: 'junior' }, { studentType: 'senior' }, { studentType: 'sophomore' }, { studentType: 'freshman' }, { studentType: 'sophomore' }, { studentType: 'freshman' } ]; let result = arr.reduce((prev, curr) => { isNaN(prev[curr.studentType]) ? prev[curr.studentType] = 1 : prev[curr.studentType]++; return prev; }, {}); console.log(result);
我在 TypeScript 中創建了一個 groupBy 函數。
export interface Group {
key: any;
items: any[];
}
export interface GroupBy {
keys: string[];
thenby?: GroupBy;
}
export const groupBy = (array: any[], grouping: GroupBy): Group[] => {
const keys = grouping.keys;
const groups = array.reduce((groups, item) => {
const group = groups.find(g => keys.every(key => item[key] === g.key[key]));
const data = Object.getOwnPropertyNames(item)
.filter(prop => !keys.find(key => key === prop))
.reduce((o, key) => ({ ...o, [key]: item[key] }), {});
return group
? groups.map(g => (g === group ? { ...g, items: [...g.items, data] } : g))
: [
...groups,
{
key: keys.reduce((o, key) => ({ ...o, [key]: item[key] }), {}),
items: [data]
}
];
}, []);
return grouping.thenby ? groups.map(g => ({ ...g, items: groupBy(g.items, grouping.thenby) })) : groups;
};
我在 StackBlitz 上做了一個演示
您可以從實現所有 C# LINQ 方法並保留其語法的manipula
包中嘗試groupBy 。
給你(兩種選擇):
function GroupBy1(arr, key) {
var group = {};
arr.forEach(val => group[val[key]] = (group[val[key]] || 0) + 1);
return group;
}
function GroupBy2(arr, key) {
return arr.reduce((group, val) => {
group[val[key]] = (group[val[key]] || 0) + 1;
return count;
}, {});
}
var arr = [
{ studentType: 'freshman' },
{ studentType: 'senior' },
{ studentType: 'freshman' },
{ studentType: 'junior' },
{ studentType: 'sophmore' },
{ studentType: 'freshman' },
{ studentType: 'freshman' },
{ studentType: 'junior' },
{ studentType: 'senior' },
{ studentType: 'senior' },
{ studentType: 'freshman' },
{ studentType: 'sophmore' },
{ studentType: 'freshman' },
{ studentType: 'sophmore' },
{ studentType: 'senior' }
];
console.log(GroupBy1(arr, 'studentType'));
console.log(GroupBy2(arr, 'studentType'));
實際上,LINQ-Group-By 返回類似於字典的東西,以組項為鍵,元素數組為列表中的對象。
這可以在 JavaScript 中輕松完成。
這是打字稿源:
// https://stackoverflow.com/questions/20310369/declare-a-delegate-type-in-typescript
// type Predicate<T, TKey> = (item: T) => TKey;
interface Predicate<T, TKey>
{
(item: T): TKey;
}
function LinqGroupBy<TSource, TKey>(source: TSource[], keySelector: Predicate<TSource, TKey>)
: { [key: string]: TSource[] }
{
if (source == null)
throw new Error("ArgumentNullException: Source");
if (keySelector == null)
throw new Error("ArgumentNullException: keySelector");
let dict: { [key: string]: TSource[]} = {};
for (let i = 0; i < source.length; ++i)
{
let key: string = keySelector(source[i]).toString();
if (!dict.hasOwnProperty(key))
{
dict[key] = [];
}
dict[key].push(source[i]);
}
return dict;
}
轉換為:
function LinqGroupBy(source, keySelector)
{
if (source == null)
throw new Error("ArgumentNullException: Source");
if (keySelector == null)
throw new Error("ArgumentNullException: keySelector");
var dict = {};
for (var i = 0; i < source.length; ++i)
{
var key = keySelector(source[i]).toString();
if (!dict.hasOwnProperty(key))
{
dict[key] = [];
}
dict[key].push(source[i]);
}
return dict;
}
由於 JavaScript 中對象的性質,這有點不穩定,但它在大多數情況下都有效。
舊帖子,但分享我自己的實現,主要靈感來自@Stefan。
我的版本沒有返回 { [key: string]: TSource[] },而是返回 { [key: string]: { key: TKey; 值:TSource[] } }
當鍵不是簡單字符串時,對我來說很有用。
interface Predicate<T, TKey> {
(item: T): TKey;
}
const linqGroupBy = <TSource, TKey>(
source: TSource[],
keySelector: Predicate<TSource, TKey>
): { [key: string]: { key: TKey; value: TSource[] } } => {
if (source == null) throw new Error("ArgumentNullException: Source");
if (keySelector == null) throw new Error("ArgumentNullException: keySelector");
const dict: { [key: string]: { key: TKey; value: TSource[] } } = {};
for (let i = 0; i < source.length; ++i) {
const k = keySelector(source[i]);
let key = String(JSON.stringify(k));
if (!dict.hasOwnProperty(key)) {
dict[key] = {
key: k,
value: [],
};
}
dict[key].value.push(source[i]);
}
return dict;
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.