在C语言中实现类似Python的groupby功能,通常需要手动处理数据分组逻辑,由于C语言本身没有内置的groupby函数,我们需要根据数据结构(如数组、链表等)和分组条件(如字段值、函数比较等)来实现。

(图片来源网络,侵删)
以下是几种实现groupby的常见方法:
方法1:基于数组的简单分组(适用于已排序数据)
如果数据已按分组键排序,可以遍历数组并按相同键的连续元素进行分组。
#include <stdio.h>
#include <string.h>
typedef struct {
int id;
char category[10];
int value;
} Data;
// 打印分组结果
void print_group(const char *key, Data *group, int size) {
printf("Group: %s\n", key);
for (int i = 0; i < size; i++) {
printf(" [%d, %s, %d]\n", group[i].id, group[i].category, group[i].value);
}
}
// 分组函数(假设数据已按category排序)
void groupby(Data *data, int size) {
if (size == 0) return;
char current_key[10];
int group_size = 0;
Data current_group[size]; // 缓存当前分组(实际中应动态分配)
strcpy(current_key, data[0].category);
for (int i = 0; i < size; i++) {
if (strcmp(data[i].category, current_key) == 0) {
current_group[group_size++] = data[i];
} else {
// 打印当前分组
print_group(current_key, current_group, group_size);
// 开始新分组
strcpy(current_key, data[i].category);
group_size = 0;
current_group[group_size++] = data[i];
}
}
// 打印最后一个分组
print_group(current_key, current_group, group_size);
}
int main() {
Data data[] = {
{1, "A", 10},
{2, "A", 20},
{3, "B", 30},
{4, "B", 40},
{5, "B", 50},
{6, "C", 60}
};
int size = sizeof(data) / sizeof(data[0]);
groupby(data, size);
return 0;
}
输出:
Group: A
[1, A, 10]
[2, A, 20]
Group: B
[3, B, 30]
[4, B, 40]
[5, B, 50]
Group: C
[6, C, 60]
方法2:使用哈希表实现高效分组(适用于大数据量)
如果数据未排序或需要高效分组,可以用哈希表(如uthash库)存储分组。

(图片来源网络,侵删)
示例:使用uthash库
- 安装uthash(单头文件库):https://github.com/troydhanson/uthash
#include <stdio.h>
#include <string.h>
#include "uthash.h"
typedef struct {
int id;
char category[10];
int value;
} Data;
typedef struct {
char key[10]; // 分组键(如category)
Data *items; // 分组中的数据(动态数组)
int count; // 分组大小
UT_hash_handle hh; // uthash句柄
} Group;
Group *groups = NULL; // 全局哈希表
// 添加数据到分组
void add_to_group(Data *data) {
Group *g;
HASH_FIND_STR(groups, data->category, g);
if (g == NULL) {
g = malloc(sizeof(Group));
strcpy(g->key, data->category);
g->items = malloc(sizeof(Data) * 10); // 初始容量(需动态扩容)
g->count = 0;
HASH_ADD_STR(groups, key, g);
}
g->items[g->count++] = *data;
}
// 打印所有分组
void print_groups() {
Group *g, *tmp;
HASH_ITER(hh, groups, g, tmp) {
printf("Group: %s\n", g->key);
for (int i = 0; i < g->count; i++) {
printf(" [%d, %s, %d]\n", g->items[i].id, g->items[i].category, g->items[i].value);
}
free(g->items);
HASH_DEL(groups, g);
free(g);
}
}
int main() {
Data data[] = {
{1, "A", 10},
{2, "A", 20},
{3, "B", 30},
{4, "B", 40},
{5, "B", 50},
{6, "C", 60}
};
int size = sizeof(data) / sizeof(data[0]);
for (int i = 0; i < size; i++) {
add_to_group(&data[i]);
}
print_groups();
return 0;
}
输出与方法1相同,但支持未排序数据且效率更高。
方法3:自定义分组函数(灵活比较)
如果分组逻辑复杂(如按范围、函数比较等),可以封装一个通用的分组函数。
#include <stdio.h>
typedef struct {
int value;
} Data;
// 自定义分组条件(示例:按value的奇偶性分组)
int group_key(Data *d) {
return d->value % 2; // 0=偶数,1=奇数
}
void groupby(Data *data, int size, int (*key_func)(Data*)) {
int group0[size], group1[size]; // 两个分组(实际中需动态分配)
int count0 = 0, count1 = 0;
for (int i = 0; i < size; i++) {
if (key_func(&data[i]) == 0) {
group0[count0++] = data[i].value;
} else {
group1[count1++] = data[i].value;
}
}
printf("Even Group:\n");
for (int i = 0; i < count0; i++) printf("%d ", group0[i]);
printf("\n");
printf("Odd Group:\n");
for (int i = 0; i < count1; i++) printf("%d ", group1[i]);
printf("\n");
}
int main() {
Data data[] = {{1}, {2}, {3}, {4}, {5}, {6}};
int size = sizeof(data) / sizeof(data[0]);
groupby(data, size, group_key);
return 0;
}
输出:
Even Group:
2 4 6
Odd Group:
1 3 5
- 已排序数据:直接遍历分组(方法1)。
- 未排序/大数据量:使用哈希表(如uthash,方法2)。
- 复杂分组逻辑:自定义分组函数(方法3)。
根据实际需求选择合适的方法,注意内存管理和错误处理。

(图片来源网络,侵删)
