Perlでリスト処理といえばmapとgrepにforeachだと思う。
たとえば、こんな感じで使える。実行すると"6 12 18 24 30"が標準出力に出力される。
#! /usr/bin/perl use strict; use warnings; # 要素に1から10を持つリストを生成する。 my @list1 = (1..10); # 各要素が3倍のリストを生成する。 my @list2 = map { $_ * 3 } @list1; # 偶数の要素のリストを生成する。 my @list3 = grep { $_ % 2 == 0 } @list2; # 各要素を表示する。 foreach (@list3) { print $_, " "; } print "\n";
これを無性にC言語でやりたくなったので実装してみた。
#include <stdio.h> #include <stdlib.h> #include "list.h" List_template(int) int multi_3(int *in, int *out) { /* 3倍する */ *out = *in * 3; return TRUE; } int is_even(int *in, int *bool) { /* 偶数か? */ *bool = (*in % 2 == 0) ? TRUE : FALSE; return TRUE; } int main() { List list1 = NULL, list2 = NULL, list3 = NULL; int i, *n; /* 要素に1から10を持つリストを生成する。 */ list1 = List_func(create, int)(); if (list1 == NULL) goto END; for (i = 1; i <= 10; i++) { if (! List_func(push, int)(list1, &i)) goto END; } /* 各要素が3倍のリストを生成する。 */ list2 = List_func(map, int)(list1, multi_3 ); if (list2 == NULL) goto END; /* 偶数の要素のリストを生成する。 */ list3 = List_func(grep, int)(list2, is_even ); if (list3 == NULL) goto END; /* 各要素を表示する。 */ List_foreach (n, list3) { printf("%d ", *n); } printf("\n"); END: List_func(delete, int)(list1); List_func(delete, int)(list2); List_func(delete, int)(list3); return 0; }
それでは恐ろしいリストの中身を。
まず、list.hの定義内容はこう。
#ifndef __LIST_H__ #define __LIST_H__ #define TRUE (1 == 1) #define FALSE (1 != 1) /* リスト型 */ typedef struct List_t *List; /* リストの生成 */ List List_create(unsigned int); /* リストの破棄 */ void List_delete(List); /* リストの末尾に追加 */ int List_push(List, const void *); /* リストの変換 */ typedef int (*List_map_func)(void *input, void *output); List List_map(List, List_map_func); /* リストのフィルタリング */ typedef int (*List_grep_func)(void *in, int *bool); List List_grep(List, List_grep_func); /* リストのイテレータが次の要素を保持しているか? */ int List_has_next(List); /* リストのイテレータをリセットし初めの要素を取得 */ void *List_begin(List); /* リストのイテレータで次の要素を取得 */ void *List_next(List); /* リストのイテレーション */ #define List_foreach(_V, _LIST) \ for (_V = List_begin(_LIST); List_has_next(_LIST); _V = List_next(_LIST) ) /* 型に応じた関数 */ #define List_func(name, type) List_##name##type #define List_template(type) \ List List_func(create, type)() { \ return List_create(sizeof(type)); \ } \ void List_func(delete, type)(List list) { \ List_delete(list); \ } \ int List_func(push, type)(List list, const type *v) { \ return List_push(list, v); \ } \ List List_func(map, type)(List list, int (*f)(type *, type *)) { \ return List_map(list, (List_map_func)f); \ } \ List List_func(grep, type)(List list, int (*f)(type *, int *)) { \ return List_grep(list, (List_grep_func)f); \ } #endif
単なる連結リスト。実装は結構長い。
#include <string.h> #include <stdlib.h> #include <stddef.h> #include "list.h" typedef struct Cell_t *Cell; /* セル型 */ typedef struct Cell_t { Cell next; /* 次のセル */ char value; /* 要素の開始 */ }; struct List_t { /* リスト型 */ size_t size; /* 要素のサイズ */ unsigned int count; /* 要素の登録数 */ Cell begin, end, now; /* 最初、最後、現在(イテレータ用) */ }; /* セルの要素のポインタを取得 */ #define CELL_VALUE(_CELL) \ ((char *)_CELL + offsetof(struct Cell_t, value)) /* セルの生成 */ static Cell Cell_create(List list) { size_t size = offsetof(struct Cell_t, value) + list->size; Cell cell = malloc(size); if (cell != NULL) cell->next = NULL; return cell; } /* セルの破棄 */ static void Cell_delete(Cell cell) { free(cell); } /* リストの生成 */ List List_create(size_t size) { List list = NULL; if (size == 0) return list; list = malloc(sizeof(struct List_t)); if (list != NULL) { list->size = size; list->count = 0; list->now = list->end = list->begin = NULL; } return list; } /* リストの破棄 */ void List_delete(List list) { if (list == NULL) return; while (list->count > 0) { Cell cell = list->begin; list->begin = cell->next; Cell_delete(cell); if (--list->count == 0) list->end = NULL; } free(list); } /* リストの末尾に追加 */ int List_push(List list,const void *value) { Cell cell = NULL; if (list == NULL) return FALSE; cell = Cell_create(list); if (cell == NULL) return FALSE; memcpy(CELL_VALUE(cell), value, list->size); if (list->end != NULL) { list->end->next = cell; } else { list->now = list->begin = cell; } list->end = cell; ++list->count; return TRUE; } /* リストの変換 */ List List_map(List list, List_map_func f) { List list2 = NULL; void *push_value = NULL; void *value; if (list == NULL) return NULL; list2 = List_create(list->size); if (list2 == NULL) return NULL; push_value = malloc(list->size); if (push_value == NULL) { List_delete(list2); return NULL; } /* List_map_func結果でリスト生成 */ List_foreach (value, list) { if (! (*f)(value, push_value)) { List_delete(list2); free(push_value); return NULL; } if (! List_push(list2, push_value) ) { List_delete(list2); free(push_value); return NULL; } } return list2; } /* リストのフィルタリング */ List List_grep(List list, List_grep_func f) { List list2 = NULL; void *value; int bool; if (list == NULL) return NULL; list2 = List_create(list->size); if (list2 == NULL) return NULL; /* List_grep_func結果が真のリストを生成 */ List_foreach (value, list) { if (! (*f)(value, &bool)) { List_delete(list2); return NULL; } if (bool) { if (! List_push(list2, value) ) { List_delete(list2); return NULL; } } } return list2; } /* リストのイテレータが次の要素を保持しているか? */ int List_has_next(List list) { if (list == NULL) return FALSE; if (list->now == NULL) return FALSE; return TRUE; } /* リストのイテレータをリセットし初めの要素を取得 */ void *List_begin(List list) { if (list == NULL) return NULL; list->now = list->begin; return CELL_VALUE(list->now); } /* リストのイテレータで次の要素を取得 */ void *List_next(List list) { if (list == NULL) return NULL; list->now = (list->now == NULL) ? NULL : list->now->next; return CELL_VALUE(list->now); }
感想。やれなくは無いけどめんどくさい。