簡體   English   中英

Javascript 相當於C# LINQ GroupBy

[英]Javascript Equivalent to C# LINQ GroupBy

這是以下問題的后續問題:

Javascript 相當於C# LINQ Select

我們正在使用 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 上做了一個演示

https://stackblitz.com/edit/typescript-ezydzv

您可以從實現所有 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM