在 Typescript 的回调函数中对 JSON 中的数据进行分组

Group data from JSON in callback function in Typescript

提问人:Jameson 提问时间:3/8/2023 更新时间:3/8/2023 访问量:96

问:

我需要编写一个函数 groupBy,它使用给定的函数对 JSON 数据中的人员进行分组。 下面是接口和 JSON 数据:

interface Person {
    name: string;
    yearOfBirth: number;
    placeOfBirth: string;
}

const input: Person[] = [
    {
        name: "Andy",
        yearOfBirth: 1984,
        placeOfBirth: "New York",
    },
    {
        name: "John",
        yearOfBirth: 1995,
        placeOfBirth: "New York",
    },
    {
        name: "Bill",
        yearOfBirth: 1995,
        placeOfBirth: "Orlando",
    },
    {
        name: "Tim",
        yearOfBirth: 1989,
        placeOfBirth: "Witchita",
    },
];

以下是我到目前为止拥有的代码,它离应有的工作还差得很远,但我是回调函数的新手,所以我一直在尝试了解它是如何工作的。

const groupBy = (input: Person[], func: (p: Person) => string): string[] => {

    let collect: string[] = [];
    for (let i = 0; i < input.length; i++) {
        collect[i] = func(input[i]);

    }
    return collect;
}

try {
    console.log(groupBy(input, (p: Person) => p.placeOfBirth));

}
catch (e: any) {
    console.log(e.message);

}

//This is the output from my current code:
[ 'New York', 'New York', 'Orlando', 'Witchita' ]

以下是使用下面的控制台 .log 调用时实际输出的方式:

//Example 1
//call the function which groups the data together from 'placeOfBirth':

console.log(groupBy(input, (p: Person) => p.placeOfBirth));

//Output from console.log:

{
  New York: [
    { name: 'Andy', yearOfBirth: 1984, placeOfBirth: 'New York' },
    { name: 'John', yearOfBirth: 1995, placeOfBirth: 'New York' }
  ],
  Orlando: [ { name: 'Bill', yearOfBirth: 1995, placeOfBirth: 'Orlando' } ],
  Witchita: [ { name: 'Tim', yearOfBirth: 1989, placeOfBirth: 'Witchita' } ]
}

//Example 2
//call the function which groups the data together from 'yearOfBirth':

console.log(groupBy(input, (p: Person) => p.yearOfBirth));

//Output from console.log:

{
  '1984': [ { name: 'Andy', yearOfBirth: 1984, placeOfBirth: 'New York' } ],
  '1995': [
    { name: 'John', yearOfBirth: 1995, placeOfBirth: 'New York' },
    { name: 'Bill', yearOfBirth: 1995, placeOfBirth: 'Orlando' }
  ],
  '1989': [ { name: 'Tim', yearOfBirth: 1989, placeOfBirth: 'Witchita' } ]
}
JavaScript JSON TypeScript 接口 回调

评论


答:

0赞 Amin Pourhadi 3/8/2023 #1

使用以下函数。传递对象数组和键名称进行分组,然后按发送的键获取分组数据:

    const groupByKey = <T>(objectArray: T[], property: string) => {
      return objectArray.reduce(
          (acc: { [x: string]: any[]; }, obj: { [x: string]: any; }) => {
          const key = obj[property];
          if (!acc[key]) {
              acc[key] = [];
          }
          acc[key].push(obj);
          return acc;
      }, 
      {});
  }

//Usage:
  const groupedData = groupByKey(personsList, 'placeOfBirth');

评论

0赞 Jameson 3/8/2023
嘿,感谢您的回复,但是我在您的代码中遇到一些错误,代码行为'(acc: { [x: string]: any[]; }, obj: { [x: string]: any; })'类型为 '(acc: { [x: string]: any[]; }, obj: { [x: string]: any; }) => { [x: string]: any[]; }' 的参数不能分配给类型为 '(previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T' 的参数。参数“acc”和“previousValue”的类型不兼容。
0赞 Florian Sénat 3/8/2023 #2

您是否专注于性能?

如果没有,您可以尝试以下操作:

function groupBy<I extends unknown>(
  input: I[],
  predicate: (i: I) => string | number
) {
  return input.reduce((curr, i) => {
    const key = predicate(i);

    return {
      ...curr,
      [key]: [...(curr[key] ?? []), i]
    };
  }, {});
}

这里有一个沙盒来尝试一下:https://codesandbox.io/s/unruffled-morse-nwjjsy?file=/src/index.ts

评论

0赞 Jameson 3/8/2023
感谢您的回复。我在您的代码中收到“curr[key]”中的错误:(参数)curr:{} 元素隐式具有“any”类型,因为“string |number“不能用于索引类型”{}”。在类型“{}”上找不到参数类型为“string”的索引签名.ts(7053)
0赞 Jameson 3/8/2023 #3

我找到了一个解决方案,最终可以将数据组合在一起。我将为其他任何寻找类似解决方案的人分享下面的代码:

interface Person {
    name: string;
    yearOfBirth: number;
    placeOfBirth: string;
}

const input: Person[] = [
    {
        name: "Andy",
        yearOfBirth: 1984,
        placeOfBirth: "New York",
    },
    {
        name: "John",
        yearOfBirth: 1995,
        placeOfBirth: "New York",
    },
    {
        name: "Bill",
        yearOfBirth: 1995,
        placeOfBirth: "Orlando",
    },
    {
        name: "Tim",
        yearOfBirth: 1989,
        placeOfBirth: "Witchita",
    },
];

function groupBy(input: Person[], groupFunc: (item: Person) => any): { [key: string]: Person[] } {
    const groups: { [key: string]: Person[] } = {};

    input.forEach(item => {
        const groupKey = groupFunc(item);
        if (!groups[groupKey]) {
            groups[groupKey] = [];
        }
        groups[groupKey].push(item);
    });

    return groups;
}

try {
    console.log(groupBy(input, (p: Person) => p.yearOfBirth));

}
catch (e: any) {
    console.log(e.message);
}

export { }