Functional GLists

Functional GLists — using GList with a functional flavor

Functions

GList * gx_list_filter ()
gboolean gx_list_every ()
gboolean gx_list_any ()
GList * gx_list_filter_in_place ()
GList * gx_list_take ()
GList * gx_list_take_in_place ()
GList * gx_list_skip ()
GList * gx_list_skip_in_place ()
GList * gx_list_map ()
GList * gx_list_map_in_place ()
gpointer gx_list_fold ()
GList * gx_list_iota ()
gint gx_list_sum ()
gint gx_list_product ()

Description

A GList is a double-linked list data structure for storing arbitrary data. GXLib offers a number of functions for GList that allow for list manipulation with a functional flavor. The functions are inspired by the list operations in Mozilla's Rust,

Scheme's SRFI-1 and their use for problems such as those from Project Euler.

Suppose we want to find the sum of the prime numbers up to 100. We can use a combination of gx_list_iota(), gx_list_filter_in_place(), gx_is_prime() and gx_list_sum() to accomplish this. You could use a one-liner for this, but let's do it in steps:

1
2
3
4
5
6
7
8
9
10
11
12
gint sum;
GList *nums;

// numbers 1..100 (inclusive)
nums = gx_list_iota (100, 1, 1);
// filter out the non-primes
nums = gx_list_filter_in_place (nums, (GXPred)gx_is_prime, NULL, NULL);
// take the sum
sum = gx_list_sum (num);

g_assert_cmpint (sum, ==, 1060);
g_list_free (nums);

Functions

gx_list_filter ()

GList *
gx_list_filter (GList *list,
                GXPred pred_func,
                gpointer user_data);

Create a GList consisting of a shallow copy of the elements of list for which the predicate function pred_func returns TRUE.

Note, for the inverse operation (removing all items for with a predicate function returns FALSE), see g_list_remove_all().

Example: getting a list of natural numbers up to 100 that can be divided by either 3 or 5

1
2
3
4
5
6
7
8
9
10
11
static gboolean div_3_5 (gint n) { return n % 3 == 0 || n % 5 == 0; }
 
GList *lst, *filtered;
  
lst = gx_list_iota (100, 1, 1); // getting a list 1..100
filtered = gx_list_filter (lst, (GXPred)div_3_5, NULL);
  
// do something useful with filtered
  
g_list_free (lst);
g_list_free (filtered);

Parameters

list

a GList

 

pred_func

a predicate function

 

user_data

a user pointer passed to pred_func .

[allow-none]

Returns

the filtered list.

[transfer full]


gx_list_every ()

gboolean
gx_list_every (GList *list,
               GXPred pred_func,
               gpointer user_data);

Check if the predicate is true for every element in list . If list is empty, this is considered TRUE.

Example: let's verify that not every number in [1..10] is a prime number:

1
2
3
4
5
6
GList *lst;

lst =  gx_list_iota (10, 1, 1);
g_assert_false (gx_list_every (lst, (GXPred)gx_is_prime, NULL));

g_list_free (lst);

Parameters

list

a GList

 

pred_func

a predicate function

 

user_data

a user pointer passed to pred_func .

[allow-none]

Returns

TRUE if pred_func returns TRUE for every element in list ; FALSE otherwise.


gx_list_any ()

gboolean
gx_list_any (GList *list,
             GXPred pred_func,
             gpointer user_data);

Check if the predicate is true for any element in list . If list is empty, this is considered FALSE.

Example: let's see if there are any prime-numbers between 20 and 30:

1
2
3
4
5
6
GList *lst;

lst =  gx_list_iota (10, 20, 1);
g_assert_true (gx_list_any (lst, (GXPred)gx_is_prime, NULL));

g_list_free (lst);

Parameters

list

a GList

 

pred_func

a predicate function

 

user_data

a user pointer passed to pred_func .

[allow-none]

Returns

TRUE if pred_func returns TRUE for at least one element in list ; FALSE otherwise.


gx_list_filter_in_place ()

GList *
gx_list_filter_in_place (GList *list,
                         GXPred pred_func,
                         gpointer user_data,
                         GDestroyNotify free_func);

Remove elements from list for which pred_func does not return TRUE. The removed elements are freed with free_func .

Note, for the inverse operation (removing all items for with a predicate function returns TRUE), see g_list_remove_all().

1
// Example

Parameters

list

a GList

 

pred_func

a predicate function

 

user_data

a user pointer passed to pred_func .

[allow-none]

free_func

function to free elements that are filtered-out.

[allow-none]

Returns

the filtered list, consisting of the remaining elements of list . Note that the start of the list may have changed.


gx_list_take ()

GList *
gx_list_take (GList *list,
              gsize n);

Take up to n elements from list ; if n is greater than the length of list , return the whole list.

Note that this uses a shallow copy of the values in list , so the list from which the elements were taken and the resulting list, share the data items.

1
2
3
4
5
6
7
8
9
10
const char* words[] = { "foo", "bar", "cuux", NULL };
GList *lst, *first2;

lst = gx_strv_to_list (words, -1);
first2 = gx_list_take (lst, 2); // foo, bar

// do something useful with first2
 
g_list_free (lst);
g_list_free (lst2);

Parameters

list

a GList

 

n

the number of elements to take

 

Returns

a new list with up to n elements; free with g_list_free().

[transfer full]


gx_list_take_in_place ()

GList *
gx_list_take_in_place (GList *list,
                       gsize n,
                       GDestroyNotify free_func);

Like gx_list_take(), but affects the list in-place; effectively, this reduces list to its first n elements, or all elements if n is greater than the length of list .

1
// Example

Parameters

list

a GList

 

n

the number of elements to take

 

free_func

function to free the removed elements.

[allow-none]

Returns

the list reduced to up to n elements.

[transfer full]


gx_list_skip ()

GList *
gx_list_skip (GList *list,
              gsize n);

Return a list of all but the first n elements of list . If n is greater than the length of list , return the empty list.

Note that this uses a shallow copy of the values in list , so the list from which the elements were taken and the resulting list, share the data items.

1
// Example

Parameters

list

a GList

 

n

the number of elements to take

 

Returns

a new list with up to n elements; free with g_list_free().

[transfer full]


gx_list_skip_in_place ()

GList *
gx_list_skip_in_place (GList *list,
                       gsize n,
                       GDestroyNotify free_func);

Remove the first n elements from list . If n is greater than the length of list , return the empty list.

1
// Example

Parameters

list

a GList

 

n

the number of elements to take

 

free_func

function to free the removed elements.

[allow-none]

Returns

a list with up to n elements; free with g_list_free() or g_list_free_full(), depending on the the.

[transfer full]


gx_list_map ()

GList *
gx_list_map (GList *list,
             GXBinaryFunc map_func,
             gpointer user_data);

Create a new list of consisting of the elements obtained by applying map_func to the corresponding elements in list .

1
2
3
4
5
6
7
8
9
10
GList *lst, *upper;
const char* cities[] = { "Aruba", "Hawaii", "Zanzibar", NULL };

lst = gx_strv_to_list (cities, -1);
upper = gx_list_map (lst, (GXBinaryFunc)g_ascii_strup, GINT_TO_POINTER(-1));

// upper contains AMSTERDAM, SAN FRANCISCO, HELSINKI

g_list_free (lst);
g_list_free_full (upper, g_free);

Parameters

list

a GList

 

map_func

a predicate function

 

user_data

a user pointer passed to map_func .

[allow-none]

Returns

the list with mapped values. Whether to free with g_list_free() or with g_list_free_full() depends on map_func .

[transfer full]


gx_list_map_in_place ()

GList *
gx_list_map_in_place (GList *list,
                      GXBinaryFunc map_func,
                      gpointer user_data,
                      GDestroyNotify free_func);

Replace each element in list with the value obtained from applying map_func to it. Free the old element using free_func .

Parameters

list

a GList

 

map_func

a predicate function

 

user_data

a user pointer passed to map_func .

[allow-none]

free_func

a function to free the replaced element.

[allow-none]

Returns

the list with mapped values.

[transfer full]


gx_list_fold ()

gpointer
gx_list_fold (GList *list,
              GXTernaryFunc fold_func,
              gpointer init,
              gpointer user_data,
              GDestroyNotify free_func);

Given a list (a, b, c), compute fold_func (fold_func (fold_func (init , a), b), c)

gx_list_fold() is useful when computing a value from the elements in a list.

For example, we can use gx_list_fold() to turn a list of strings into a single string, wit the elements separated by ", ". This is similar to what g_build_path() does, but uses lists:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
static char*
chain (const char *s1, const char *s2, const char *sepa)
{
  if (!s1)
    return g_strdup (s2);
  else
    return g_strconcat (s1, sepa, s2, NULL);
}

GList *lst;
char  *str;
const char* cities[] = { "Amsterdam", "San Francisco", "Helsinki", NULL };

lst = gx_strv_to_list ((gchar**)cities, -1);
str = gx_list_fold (lst, (GXTernaryFunc)chain, NULL, "; ", g_free);

g_assert_cmpstr (str, ==, "Amsterdam; San Francisco; Helsinki");

g_free (str);
g_list_free (lst);

Parameters

list

a GList

 

fold_func

a ternary function

 

init

the start value

 

user_data

a user pointer passed to fold_func .

[allow-none]

free_func

a function to free the intermediate values.

[allow-none]

Returns

the computed value.

[transfer full]


gx_list_iota ()

GList *
gx_list_iota (gsize count,
              gint start,
              gsize step);

Create a GList with count numbers starting at start , and then increasing by step ; similar to Scheme's SRFI-1's iota procedure.

For example, to get the first 100 even numbers:

1
2
3
4
GList *lst;
lst = gx_list_iota (100, 0, 2);
// do something with lst
g_list_free (lst);

Parameters

count

number of elements to generate

 

start

the start value

 

step

the step size, must be > 0

 

Returns

a list with numbers. Free with g_free().

[transfer full]


gx_list_sum ()

gint
gx_list_sum (GList *list);

Calculate the sum of a list of integers. This is an optimized shorthand for

1
2
sum = GPOINTER_TO_INT(gx_list_fold (list, (GTernaryFunc)gx_plus,
                      GINT_TO_POINTER(0), NULL, NULL));

Parameters

list

a GList

 

Returns

the sum of the integers in list .

[transfer full]


gx_list_product ()

gint
gx_list_product (GList *list);

Calculate the product of a list of integers. This is an optimized shorthand for

1
2
sum = GPOINTER_TO_INT(gx_list_fold (list, (GTernaryFunc)gx_times,
                      GINT_TO_POINTER(1), NULL, NULL));

Parameters

list

a GList

 

Returns

the product of the integers in list .

[transfer full]

Types and Values