This post is my personal reference for functional programming with purrr
package. I often find myself to search on google/stackoverflow “how to” iterate over this and that so it make sense to put it together somewhere. This post is vastly based on brilliant Jenny Bryan´s purrr tutorial and focus on nested lists / list-columns.
library(repurrrsive)
library(tidyverse)
Two datasets from repurrrsive
package to practise on:
got_char
Game of Thrones characters dataset.gh_repos
Github repositories dataset.
Start simple
- using
str
and it´smax.level
andlist.len
argument - using
View()
function in RStudio
# is it even list?
got_chars %>% class
## [1] "list"
# list.len limits each nesting level to x items (by default list.len = 99)
# in case of more nested lists use max.level argument, by default all levels are shown
got_chars %>% str(list.len = 3)
## List of 30
## $ :List of 18
## ..$ url : chr "https://www.anapioficeandfire.com/api/characters/1022"
## ..$ id : int 1022
## ..$ name : chr "Theon Greyjoy"
## .. [list output truncated]
## $ :List of 18
## ..$ url : chr "https://www.anapioficeandfire.com/api/characters/1052"
## ..$ id : int 1052
## ..$ name : chr "Tyrion Lannister"
## .. [list output truncated]
## $ :List of 18
## ..$ url : chr "https://www.anapioficeandfire.com/api/characters/1074"
## ..$ id : int 1074
## ..$ name : chr "Victarion Greyjoy"
## .. [list output truncated]
## [list output truncated]
So got_char
is a list of 30 lists, each with 18 items.
We can get this information this way too:
# number of items (lists in this case) at level 0
got_chars %>% length()
## [1] 30
# number of items at level 1
got_chars %>% map_int(length)
## [1] 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18
## [24] 18 18 18 18 18 18 18
Or using View()
function in RStudio. I prefer it.
..down to 30 lists
Now I want all items just from first list:
got_chars[1] %>% str
## List of 1
## $ :List of 18
## ..$ url : chr "https://www.anapioficeandfire.com/api/characters/1022"
## ..$ id : int 1022
## ..$ name : chr "Theon Greyjoy"
## ..$ gender : chr "Male"
## ..$ culture : chr "Ironborn"
## ..$ born : chr "In 278 AC or 279 AC, at Pyke"
## ..$ died : chr ""
## ..$ alive : logi TRUE
## ..$ titles : chr [1:3] "Prince of Winterfell" "Captain of Sea Bitch" "Lord of the Iron Islands (by law of the green lands)"
## ..$ aliases : chr [1:4] "Prince of Fools" "Theon Turncloak" "Reek" "Theon Kinslayer"
## ..$ father : chr ""
## ..$ mother : chr ""
## ..$ spouse : chr ""
## ..$ allegiances: chr "House Greyjoy of Pyke"
## ..$ books : chr [1:3] "A Game of Thrones" "A Storm of Swords" "A Feast for Crows"
## ..$ povBooks : chr [1:2] "A Clash of Kings" "A Dance with Dragons"
## ..$ tvSeries : chr [1:6] "Season 1" "Season 2" "Season 3" "Season 4" ...
## ..$ playedBy : chr "Alfie Allen"
Here is good to realize:
a) that single [
returns always list
b) even if 5th element is pulled, the index of outcome will be 1, not 5.
got_chars[5]
## [[1]]
## [[1]]$url
## [1] "https://www.anapioficeandfire.com/api/characters/1166"
##
## [[1]]$id
## [1] 1166
##
## [[1]]$name
## [1] "Areo Hotah"
##
## [[1]]$gender
## [1] "Male"
##
## [[1]]$culture
## [1] "Norvoshi"
##
## [[1]]$born
## [1] "In 257 AC or before, at Norvos"
##
## [[1]]$died
## [1] ""
##
## [[1]]$alive
## [1] TRUE
##
## [[1]]$titles
## [1] "Captain of the Guard at Sunspear"
##
## [[1]]$aliases
## [1] ""
##
## [[1]]$father
## [1] ""
##
## [[1]]$mother
## [1] ""
##
## [[1]]$spouse
## [1] ""
##
## [[1]]$allegiances
## [1] "House Nymeros Martell of Sunspear"
##
## [[1]]$books
## [1] "A Game of Thrones" "A Clash of Kings" "A Storm of Swords"
##
## [[1]]$povBooks
## [1] "A Feast for Crows" "A Dance with Dragons"
##
## [[1]]$tvSeries
## [1] "Season 5" "Season 6"
##
## [[1]]$playedBy
## [1] "DeObia Oparei"
Now, I want all content of items just from first list:
# outcome is a list again but with one level only
got_chars[[1]] %>% str
## List of 18
## $ url : chr "https://www.anapioficeandfire.com/api/characters/1022"
## $ id : int 1022
## $ name : chr "Theon Greyjoy"
## $ gender : chr "Male"
## $ culture : chr "Ironborn"
## $ born : chr "In 278 AC or 279 AC, at Pyke"
## $ died : chr ""
## $ alive : logi TRUE
## $ titles : chr [1:3] "Prince of Winterfell" "Captain of Sea Bitch" "Lord of the Iron Islands (by law of the green lands)"
## $ aliases : chr [1:4] "Prince of Fools" "Theon Turncloak" "Reek" "Theon Kinslayer"
## $ father : chr ""
## $ mother : chr ""
## $ spouse : chr ""
## $ allegiances: chr "House Greyjoy of Pyke"
## $ books : chr [1:3] "A Game of Thrones" "A Storm of Swords" "A Feast for Crows"
## $ povBooks : chr [1:2] "A Clash of Kings" "A Dance with Dragons"
## $ tvSeries : chr [1:6] "Season 1" "Season 2" "Season 3" "Season 4" ...
## $ playedBy : chr "Alfie Allen"
Good to realize:
got_chars[1] %>% names
## NULL
vs.
got_chars[[1]] %>% names
## [1] "url" "id" "name" "gender" "culture"
## [6] "born" "died" "alive" "titles" "aliases"
## [11] "father" "mother" "spouse" "allegiances" "books"
## [16] "povBooks" "tvSeries" "playedBy"
Extract name
from each list:
got_chars %>% map_chr(~.$name)
## [1] "Theon Greyjoy" "Tyrion Lannister" "Victarion Greyjoy"
## [4] "Will" "Areo Hotah" "Chett"
## [7] "Cressen" "Arianne Martell" "Daenerys Targaryen"
## [10] "Davos Seaworth" "Arya Stark" "Arys Oakheart"
## [13] "Asha Greyjoy" "Barristan Selmy" "Varamyr"
## [16] "Brandon Stark" "Brienne of Tarth" "Catelyn Stark"
## [19] "Cersei Lannister" "Eddard Stark" "Jaime Lannister"
## [22] "Jon Connington" "Jon Snow" "Aeron Greyjoy"
## [25] "Kevan Lannister" "Melisandre" "Merrett Frey"
## [28] "Quentyn Martell" "Samwell Tarly" "Sansa Stark"
or
got_chars %>% map_chr(~.x$name)
## [1] "Theon Greyjoy" "Tyrion Lannister" "Victarion Greyjoy"
## [4] "Will" "Areo Hotah" "Chett"
## [7] "Cressen" "Arianne Martell" "Daenerys Targaryen"
## [10] "Davos Seaworth" "Arya Stark" "Arys Oakheart"
## [13] "Asha Greyjoy" "Barristan Selmy" "Varamyr"
## [16] "Brandon Stark" "Brienne of Tarth" "Catelyn Stark"
## [19] "Cersei Lannister" "Eddard Stark" "Jaime Lannister"
## [22] "Jon Connington" "Jon Snow" "Aeron Greyjoy"
## [25] "Kevan Lannister" "Melisandre" "Merrett Frey"
## [28] "Quentyn Martell" "Samwell Tarly" "Sansa Stark"
or
got_chars %>% map_chr("name")
## [1] "Theon Greyjoy" "Tyrion Lannister" "Victarion Greyjoy"
## [4] "Will" "Areo Hotah" "Chett"
## [7] "Cressen" "Arianne Martell" "Daenerys Targaryen"
## [10] "Davos Seaworth" "Arya Stark" "Arys Oakheart"
## [13] "Asha Greyjoy" "Barristan Selmy" "Varamyr"
## [16] "Brandon Stark" "Brienne of Tarth" "Catelyn Stark"
## [19] "Cersei Lannister" "Eddard Stark" "Jaime Lannister"
## [22] "Jon Connington" "Jon Snow" "Aeron Greyjoy"
## [25] "Kevan Lannister" "Melisandre" "Merrett Frey"
## [28] "Quentyn Martell" "Samwell Tarly" "Sansa Stark"
or straight to tibble:
got_chars %>% map_df(~.[c("name", "gender")])
## # A tibble: 30 x 2
## name gender
## <chr> <chr>
## 1 Theon Greyjoy Male
## 2 Tyrion Lannister Male
## 3 Victarion Greyjoy Male
## 4 Will Male
## 5 Areo Hotah Male
## 6 Chett Male
## 7 Cressen Male
## 8 Arianne Martell Female
## 9 Daenerys Targaryen Female
## 10 Davos Seaworth Male
## # ... with 20 more rows
What if I want “aliases” too?
got_chars %>% map_df(~.[c("name", "gender", "aliases")])
## Error: Argument 3 must be length 1, not 4
..it doesn´t work beacause some characters have more than one aliase.
But this does:
# alias will be list-colum ("nested")
df <- tibble(
name = got_chars %>% map_chr("name"),
id = got_chars %>% map_int("id"),
gender = got_chars %>% map_chr("gender"),
aliases = got_chars %>% map("aliases")
)
df
## # A tibble: 30 x 4
## name id gender aliases
## <chr> <int> <chr> <list>
## 1 Theon Greyjoy 1022 Male <chr [4]>
## 2 Tyrion Lannister 1052 Male <chr [11]>
## 3 Victarion Greyjoy 1074 Male <chr [1]>
## 4 Will 1109 Male <chr [1]>
## 5 Areo Hotah 1166 Male <chr [1]>
## 6 Chett 1267 Male <chr [1]>
## 7 Cressen 1295 Male <chr [1]>
## 8 Arianne Martell 130 Female <chr [1]>
## 9 Daenerys Targaryen 1303 Female <chr [11]>
## 10 Davos Seaworth 1319 Male <chr [5]>
## # ... with 20 more rows
..it works because alias is bind as list-colum (“nested”)
Using unnest
comes handy now? Nope yet..
df %>%
unnest()
## Warning: `cols` is now required.
## Please use `cols = c(aliases)`
## # A tibble: 114 x 4
## name id gender aliases
## <chr> <int> <chr> <chr>
## 1 Theon Greyjoy 1022 Male Prince of Fools
## 2 Theon Greyjoy 1022 Male Theon Turncloak
## 3 Theon Greyjoy 1022 Male Reek
## 4 Theon Greyjoy 1022 Male Theon Kinslayer
## 5 Tyrion Lannister 1052 Male The Imp
## 6 Tyrion Lannister 1052 Male Halfman
## 7 Tyrion Lannister 1052 Male The boyman
## 8 Tyrion Lannister 1052 Male Giant of Lannister
## 9 Tyrion Lannister 1052 Male Lord Tywin's Doom
## 10 Tyrion Lannister 1052 Male Lord Tywin's Bane
## # ... with 104 more rows
..it is because some of alias has NA (NULL) value (# NULL are the list-col equivalent of NAs):
df$aliases %>% map_lgl(is.null)
## [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
## [12] FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE
## [23] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
We can use replace_na
to replace NULL to "" or whatever and unnest
afterwards.
df %>%
replace_na(list(aliases=list(""))) %>%
unnest()
## Warning: `cols` is now required.
## Please use `cols = c(aliases)`
## # A tibble: 115 x 4
## name id gender aliases
## <chr> <int> <chr> <chr>
## 1 Theon Greyjoy 1022 Male Prince of Fools
## 2 Theon Greyjoy 1022 Male Theon Turncloak
## 3 Theon Greyjoy 1022 Male Reek
## 4 Theon Greyjoy 1022 Male Theon Kinslayer
## 5 Tyrion Lannister 1052 Male The Imp
## 6 Tyrion Lannister 1052 Male Halfman
## 7 Tyrion Lannister 1052 Male The boyman
## 8 Tyrion Lannister 1052 Male Giant of Lannister
## 9 Tyrion Lannister 1052 Male Lord Tywin's Doom
## 10 Tyrion Lannister 1052 Male Lord Tywin's Bane
## # ... with 105 more rows
To tibble asap
..extracting using mutate+map+unnest ..allows iterative approach - more decomposed code and faster debugging
a) directly to tibble
tibble(name = got_chars %>% map_chr(~.$name)) %>%
mutate(id = got_chars %>% map_int(~.$id)) %>%
mutate(aliases = got_chars %>% map(~.$aliases)) %>%
replace_na(list(aliases = list(""))) %>%
unnest(aliases)
## # A tibble: 115 x 3
## name id aliases
## <chr> <int> <chr>
## 1 Theon Greyjoy 1022 Prince of Fools
## 2 Theon Greyjoy 1022 Theon Turncloak
## 3 Theon Greyjoy 1022 Reek
## 4 Theon Greyjoy 1022 Theon Kinslayer
## 5 Tyrion Lannister 1052 The Imp
## 6 Tyrion Lannister 1052 Halfman
## 7 Tyrion Lannister 1052 The boyman
## 8 Tyrion Lannister 1052 Giant of Lannister
## 9 Tyrion Lannister 1052 Lord Tywin's Doom
## 10 Tyrion Lannister 1052 Lord Tywin's Bane
## # ... with 105 more rows
b) set_names
and enframe
the list (in fact it is directly to tibble too)
got_chars %>%
set_names(., got_chars %>% map_chr(~.$name)) %>%
enframe(name = "name", value = "data") %>%
mutate(id = data %>% map_int(~.$id)) %>%
# or
mutate(id_2 = data %>% map(~.$id) %>% unlist) %>%
mutate(aliases = data %>% map(~.$aliases)) %>%
replace_na(list(aliases = list(""))) %>%
unnest(aliases, .drop = FALSE)
## Warning: The `.drop` argument of `unnest()` is deprecated as of tidyr 1.0.0.
## All list-columns are now preserved.
## This warning is displayed once per session.
## Call `lifecycle::last_warnings()` to see where this warning was generated.
## # A tibble: 115 x 5
## name data id id_2 aliases
## <chr> <list> <int> <int> <chr>
## 1 Theon Greyjoy <named list [18]> 1022 1022 Prince of Fools
## 2 Theon Greyjoy <named list [18]> 1022 1022 Theon Turncloak
## 3 Theon Greyjoy <named list [18]> 1022 1022 Reek
## 4 Theon Greyjoy <named list [18]> 1022 1022 Theon Kinslayer
## 5 Tyrion Lannister <named list [18]> 1052 1052 The Imp
## 6 Tyrion Lannister <named list [18]> 1052 1052 Halfman
## 7 Tyrion Lannister <named list [18]> 1052 1052 The boyman
## 8 Tyrion Lannister <named list [18]> 1052 1052 Giant of Lannister
## 9 Tyrion Lannister <named list [18]> 1052 1052 Lord Tywin's Doom
## 10 Tyrion Lannister <named list [18]> 1052 1052 Lord Tywin's Bane
## # ... with 105 more rows
More nested stuff
# explore gh_repos list
gh_repos[[1]] %>% str(max.level = 4, list.len = 4)
## List of 30
## $ :List of 68
## ..$ id : int 61160198
## ..$ name : chr "after"
## ..$ full_name : chr "gaborcsardi/after"
## ..$ owner :List of 17
## .. ..$ login : chr "gaborcsardi"
## .. ..$ id : int 660288
## .. ..$ avatar_url : chr "https://avatars.githubusercontent.com/u/660288?v=3"
## .. ..$ gravatar_id : chr ""
## .. .. [list output truncated]
## .. [list output truncated]
## $ :List of 68
## ..$ id : int 40500181
## ..$ name : chr "argufy"
## ..$ full_name : chr "gaborcsardi/argufy"
## ..$ owner :List of 17
## .. ..$ login : chr "gaborcsardi"
## .. ..$ id : int 660288
## .. ..$ avatar_url : chr "https://avatars.githubusercontent.com/u/660288?v=3"
## .. ..$ gravatar_id : chr ""
## .. .. [list output truncated]
## .. [list output truncated]
## $ :List of 68
## ..$ id : int 36442442
## ..$ name : chr "ask"
## ..$ full_name : chr "gaborcsardi/ask"
## ..$ owner :List of 17
## .. ..$ login : chr "gaborcsardi"
## .. ..$ id : int 660288
## .. ..$ avatar_url : chr "https://avatars.githubusercontent.com/u/660288?v=3"
## .. ..$ gravatar_id : chr ""
## .. .. [list output truncated]
## .. [list output truncated]
## $ :List of 68
## ..$ id : int 34924886
## ..$ name : chr "baseimports"
## ..$ full_name : chr "gaborcsardi/baseimports"
## ..$ owner :List of 17
## .. ..$ login : chr "gaborcsardi"
## .. ..$ id : int 660288
## .. ..$ avatar_url : chr "https://avatars.githubusercontent.com/u/660288?v=3"
## .. ..$ gravatar_id : chr ""
## .. .. [list output truncated]
## .. [list output truncated]
## [list output truncated]
or again using View()
function in RStudio. I prefer it because you can easily miss something when using str
(yes, it sounds strange, but that is my experiance with complicated lists). There are two major advantages:
- Using
View
you can explore single element down to latest element without extending the list with other elements (unlikestr
) - Using
View
you can get direct address to now-matter-how-much-scary-nested element (can be done withstr
too actually, but more complicated way)
or
# number of item at level 0
gh_repos %>% length()
## [1] 6
# number of item at level 1
gh_repos %>% map_int(length)
## [1] 30 30 30 26 30 30
# number of item at level 2
gh_repos %>% map(map_int, length)
## [[1]]
## [1] 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68
## [24] 68 68 68 68 68 68 68
##
## [[2]]
## [1] 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68
## [24] 68 68 68 68 68 68 68
##
## [[3]]
## [1] 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68
## [24] 68 68 68 68 68 68 68
##
## [[4]]
## [1] 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68
## [24] 68 68 68
##
## [[5]]
## [1] 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68
## [24] 68 68 68 68 68 68 68
##
## [[6]]
## [1] 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68 68
## [24] 68 68 68 68 68 68 68
..more about last one later
..gh_repos
is list of 6 lists, each with 30 (except one with 26 lists), each with 68 items
# exctract name
gh_repos %>% map(~.[[1]][["name"]])
## [[1]]
## [1] "after"
##
## [[2]]
## [1] "2013-11_sfu"
##
## [[3]]
## [1] "advdatasci"
##
## [[4]]
## [1] "2016-14"
##
## [[5]]
## [1] "ampolcourse"
##
## [[6]]
## [1] "aqi_pdf"
..but it is NOT correct. Why? Because this is just item “name” from each first sub-list. We need somehow iterate over index map_chr(~.[[i]][[“name”]])
gh_repos %>% map(function(x){map_chr(x, ~.$name)
}) %>%
str()
## List of 6
## $ : chr [1:30] "after" "argufy" "ask" "baseimports" ...
## $ : chr [1:30] "2013-11_sfu" "2014-01-27-miami" "2014-05-12-ubc" "2015-02-23_bryan-fields-talk" ...
## $ : chr [1:30] "advdatasci" "advdatasci-swirl" "advdatasci16" "advdatasci_swirl" ...
## $ : chr [1:26] "2016-14" "choroplethrCaCensusTract" "choroplethrUTCensusTract" "CountyHealthApp" ...
## $ : chr [1:30] "ampolcourse" "apsa-leeper.bst" "arco" "astrojs" ...
## $ : chr [1:30] "aqi_pdf" "catan_card_game" "colourlovers_patterns" "convertagd" ...
That´s it! or
gh_repos %>% map(map_chr, ~.$name) %>%
str()
## List of 6
## $ : chr [1:30] "after" "argufy" "ask" "baseimports" ...
## $ : chr [1:30] "2013-11_sfu" "2014-01-27-miami" "2014-05-12-ubc" "2015-02-23_bryan-fields-talk" ...
## $ : chr [1:30] "advdatasci" "advdatasci-swirl" "advdatasci16" "advdatasci_swirl" ...
## $ : chr [1:26] "2016-14" "choroplethrCaCensusTract" "choroplethrUTCensusTract" "CountyHealthApp" ...
## $ : chr [1:30] "ampolcourse" "apsa-leeper.bst" "arco" "astrojs" ...
## $ : chr [1:30] "aqi_pdf" "catan_card_game" "colourlovers_patterns" "convertagd" ...
That´s it again. or
gh_repos %>% modify_depth(2, ~.$name) %>%
str(list.len = 4)
## List of 6
## $ :List of 30
## ..$ : chr "after"
## ..$ : chr "argufy"
## ..$ : chr "ask"
## ..$ : chr "baseimports"
## .. [list output truncated]
## $ :List of 30
## ..$ : chr "2013-11_sfu"
## ..$ : chr "2014-01-27-miami"
## ..$ : chr "2014-05-12-ubc"
## ..$ : chr "2015-02-23_bryan-fields-talk"
## .. [list output truncated]
## $ :List of 30
## ..$ : chr "advdatasci"
## ..$ : chr "advdatasci-swirl"
## ..$ : chr "advdatasci16"
## ..$ : chr "advdatasci_swirl"
## .. [list output truncated]
## $ :List of 26
## ..$ : chr "2016-14"
## ..$ : chr "choroplethrCaCensusTract"
## ..$ : chr "choroplethrUTCensusTract"
## ..$ : chr "CountyHealthApp"
## .. [list output truncated]
## [list output truncated]
# modify_depth is a little bit difficult to abstract and the disadvantage is that it return list only, there isn´t modify_depth_char equivalent
Now, we will extract owner
list, more specifically login
variable. We can notice it is duplicated in each list = useful to set as name. The index = 1 is OK as we will extract just one (first) item from list as all others are the same.
# extract login
gh_repos %>% map_chr(~.[[1]][["owner"]][["login"]])
## [1] "gaborcsardi" "jennybc" "jtleek" "juliasilge" "leeper"
## [6] "masalmon"
or
# extract login
gh_repos %>% map_chr(~.[[1]]$owner$login)
## [1] "gaborcsardi" "jennybc" "jtleek" "juliasilge" "leeper"
## [6] "masalmon"
or
gh_repos %>% map_chr(c(1,4,1))
## [1] "gaborcsardi" "jennybc" "jtleek" "juliasilge" "leeper"
## [6] "masalmon"
The best practise - put it all together
# explore the list first with View() or str, understand the data
# put list into tibble using enframe (list must have names) or set_names first = get the address to logical element for your names
gh_repos %>%
set_names(., map_chr(gh_repos, ~.[[1]]$owner$login)) %>%
enframe(name = "name", value = "data") -> t
t
## # A tibble: 6 x 2
## name data
## <chr> <list>
## 1 gaborcsardi <list [30]>
## 2 jennybc <list [30]>
## 3 jtleek <list [30]>
## 4 juliasilge <list [26]>
## 5 leeper <list [30]>
## 6 masalmon <list [30]>
..here is good to realize that data
is basically replicated gh_repos
.
# now mutate whatever you want by extracting using mutate + map depending on level of nest
t %>%
mutate(package = data %>% map(map_chr, ~.$name)) %>%
# the index = 1 is OK here as we will extract just one (first) item from sub-list as all others are the same.
mutate(owner_url = data %>% map_chr(~.[[1]]$owner$url)) %>%
unnest(package, .drop = FALSE)
## # A tibble: 176 x 4
## name data package owner_url
## <chr> <list> <chr> <chr>
## 1 gaborcsardi <list [30]> after https://api.github.com/users/gaborcs~
## 2 gaborcsardi <list [30]> argufy https://api.github.com/users/gaborcs~
## 3 gaborcsardi <list [30]> ask https://api.github.com/users/gaborcs~
## 4 gaborcsardi <list [30]> baseimpor~ https://api.github.com/users/gaborcs~
## 5 gaborcsardi <list [30]> citest https://api.github.com/users/gaborcs~
## 6 gaborcsardi <list [30]> clisymbols https://api.github.com/users/gaborcs~
## 7 gaborcsardi <list [30]> cmaker https://api.github.com/users/gaborcs~
## 8 gaborcsardi <list [30]> cmark https://api.github.com/users/gaborcs~
## 9 gaborcsardi <list [30]> conditions https://api.github.com/users/gaborcs~
## 10 gaborcsardi <list [30]> crayon https://api.github.com/users/gaborcs~
## # ... with 166 more rows