Reputation:
I have a list like this
a toy data like this
ltd <- list(structure(list(Abund = c("BROS", "KIS", "TTHS",
"MKS"), `Value: F111: cold, Sample1` = c("1.274e7", "",
"", "2.301e7"), `Value: F111: warm, Sample1` = c("", "",
"", "")), .Names = c("Abund", "Value: F111: cold, Sample1",
"Value: F111: warm, Sample1"), row.names = c(NA, 4L), class = "data.frame"),
structure(list(Abund = c("BROS", "TMS", "KIS",
"HERS"), `Value: F216: cold, Sample2` = c("1.670e6",
"4.115e7", "", "1.302e7"), `Value: F216: warm, Sample2` = c("",
"2.766e7", "", "1.396e7")), .Names = c("Abund", "Value: F216: cold, Sample2",
"Value: F216: warm, Sample2"), row.names = c(NA, 4L), class = "data.frame"),
structure(list(Abund = c("BROS", "TMS", "KIS",
"HERS"), `Value: F655: cold, Sample3` = c("7.074e4",
"1.038e7", "", "7.380e5"), `Value: F655: warm, Sample3` = c("",
"6.874e6", "", "7.029e5")), .Names = c("Abund", "Value: F655: cold, Sample3",
"Value: F655: warm, Sample3"), row.names = c(NA, 4L), class = "data.frame"))
List of 5000
$ :'data.frame': 397 obs. of 3 variables:
..$ Abund : chr [1:363] "TTT" "MMM" "GTR" "NLM" ...
..$ Value: F111: Warm, Sample1: chr [1:363] "1.274e7" "" "" "2.301e7" ...
..$ Value: F111: Cold, Sample1: chr [1:363] "" "" "" "" ...
$ :'data.frame': 673 obs. of 3 variables:
..$ Abund : chr [1:673] "MGL" "KKK" "LFT" "NKL" ...
..$ Value: F216: Warm, Sample2: chr [1:673] "1.670e6" "4.115e7" "" "1.302e7" ...
..$ Value: F216: Cold, Sample2: chr [1:673] "" "2.766e7" "" "1.396e7" ...
$ :'data.frame': 779 obs. of 3 variables:
..$ Abund : chr [1:779] "TTLS" "KIS" "KISA" "LISU" ...
..$ Value: F655: Warm, Sample3: chr [1:779] "7.074e4" "1.038e7" "" "7.380e5" ...
..$ Value: F655: Cold, Sample3: chr [1:779] "" "6.874e6" "" "7.029e5" ...
$ :'data.frame': 387 obs. of 3 variables:
..$ Abund : chr [1:387] "BRO" "BIA" "KIA" "TTHS" ...
..$ Value: F57: Warm, Sample4: chr [1:387] "6.910e6" "" "2.435e7" "3.924e6" ...
..$ Value: F57: Cold, Sample4: chr [1:387] "5.009e6" "" "" "3.624e6" ...
$ :'data.frame': 543 obs. of 3 variables:
I want to give unique names to the abund starting from 1 to whatever it has , so the output should look like
So a disire output looks like below. I have to just write blah blah that this web allow me to post my question otherwise it does not allow
List of 5000
$ :'data.frame': 397 obs. of 3 variables:
..$ Abund1 : chr [1:363] "TTT" "MMM" "GTR" "NLM" ...
..$ Value: F111: Warm, Sample1: chr [1:363] "1.274e7" "" "" "2.301e7" ...
..$ Value: F111: Cold, Sample1: chr [1:363] "" "" "" "" ...
$ :'data.frame': 673 obs. of 3 variables:
..$ Abund2 : chr [1:673] "MGL" "KKK" "LFT" "NKL" ...
..$ Value: F216: Warm, Sample2: chr [1:673] "1.670e6" "4.115e7" "" "1.302e7" ...
..$ Value: F216: Cold, Sample2: chr [1:673] "" "2.766e7" "" "1.396e7" ...
$ :'data.frame': 779 obs. of 3 variables:
..$ Abund3 : chr [1:779] "TTLS" "KIS" "KISA" "LISU" ...
..$ Value: F655: Warm, Sample3: chr [1:779] "7.074e4" "1.038e7" "" "7.380e5" ...
..$ Value: F655: Cold, Sample3: chr [1:779] "" "6.874e6" "" "7.029e5" ...
$ :'data.frame': 387 obs. of 3 variables:
..$ Abund4 : chr [1:387] "BRO" "BIA" "KIA" "TTHS" ...
..$ Value: F57: Warm, Sample4: chr [1:387] "6.910e6" "" "2.435e7" "3.924e6" ...
..$ Value: F57: Cold, Sample4: chr [1:387] "5.009e6" "" "" "3.624e6" ...
Upvotes: 0
Views: 78
Reputation: 47320
In base R you can do it this way :
ltd2 <- Map(function(x,y) {names(x)[1] <- paste0(names(x)[1],y);x},ltd,seq(ltd))
str(ltd2)
# List of 3
# $ :'data.frame': 4 obs. of 3 variables:
# ..$ Abund1 : chr [1:4] "BROS" "KIS" "TTHS" "MKS"
# ..$ Value: F111: cold, Sample1: chr [1:4] "1.274e7" "" "" "2.301e7"
# ..$ Value: F111: warm, Sample1: chr [1:4] "" "" "" ""
# $ :'data.frame': 4 obs. of 3 variables:
# ..$ Abund2 : chr [1:4] "BROS" "TMS" "KIS" "HERS"
# ..$ Value: F216: cold, Sample2: chr [1:4] "1.670e6" "4.115e7" "" "1.302e7"
# ..$ Value: F216: warm, Sample2: chr [1:4] "" "2.766e7" "" "1.396e7"
# $ :'data.frame': 4 obs. of 3 variables:
# ..$ Abund3 : chr [1:4] "BROS" "TMS" "KIS" "HERS"
# ..$ Value: F655: cold, Sample3: chr [1:4] "7.074e4" "1.038e7" "" "7.380e5"
# ..$ Value: F655: warm, Sample3: chr [1:4] "" "6.874e6" "" "7.029e5"
But I would use purrr::imap
and dplyr::rename_at
for same result:
library(purrr)
library(dplyr)
ltd3 <- imap(ltd,~rename_at(.,1,paste0,.y))
Upvotes: 0
Reputation: 160447
To solve a problem like this, instead of attacking the big problem up front, it's best to solve one piece of it at a time. If we look at just one frame from your list, I'll call it x
:
x <- structure(list(Abund = c("BROS", "KIS", "TTHS",
"MKS"), `Value: F111: cold, Sample1` = c("1.274e7", "",
"", "2.301e7"), `Value: F111: warm, Sample1` = c("", "",
"", "")), .Names = c("Abund", "Value: F111: cold, Sample1",
"Value: F111: warm, Sample1"), row.names = c(NA, 4L), class = "data.frame")
str(x)
# 'data.frame': 4 obs. of 3 variables:
# $ Abund111 : chr "BROS" "KIS" "TTHS" "MKS"
# $ Value: F111: cold, Sample1: chr "1.274e7" "" "" "2.301e7"
# $ Value: F111: warm, Sample1: chr "" "" "" ""
You had originally wanted to append the number after the "F" in the other column names. I'll attack that first, and then if you really want it, I'll also do the "append an incrementing number" thing.
Write a function that finds the "F" number within the second column name and appends it to the first column name. (I'm wondering if there are more diverse patterns of headers in your full dataset; I'm confident that the regex we use here can easily be manipulated to handle them, given enough varying samples.)
somefunc <- function(x) {
cn2 <- colnames(x)[2]
Fnum <- gsub(".*F([0-9]+).*", "\\1", cn2)
colnames(x)[1] <- paste0(colnames(x)[1], Fnum)
x
}
A brief explanation:
colnames(x)[2]
just retrieves the second one; I'm assuming that we can base everything on the presence and makeup of this second columngsub(".*F([0-9]+).*", "\\1", cn2)
extracts just the numbers after "F"; for the record, if it weren't for the Sample
, we might be able to discard any non-number, but I chose being safe here.
.*
matches zero or more "anything" characters; sandwiching the rest with this on both sides of our group is essentially discarding all but the number we wantF
the literal "F"(...)
this is a group, saved for later (referenced with the \\1
in the replacement string, the second argument to gsub
)[0-9]+
accepts anything within the brackets, which can be literals ([acf]
matches the three letters) or a range ([0-9A-F]
matches any digit and any letters between A and F); the +
makes it "one or more" (contrasting with the *
before which is zero or more)colnames(x)[1] <- ...
reassign the first column nameThe work on the "single frame":
str( somefunc(x) )
# 'data.frame': 4 obs. of 3 variables:
# $ Abund111 : chr "BROS" "KIS" "TTHS" "MKS"
# $ Value: F111: cold, Sample1: chr "1.274e7" "" "" "2.301e7"
# $ Value: F111: warm, Sample1: chr "" "" "" ""
So now the question is how to apply this function that operates on one frame across a list of frames. lapply
to the rescue:
str(lapply(ltd, somefunc))
# List of 3
# $ :'data.frame': 4 obs. of 3 variables:
# ..$ Abund111 : chr [1:4] "BROS" "KIS" "TTHS" "MKS"
# ..$ Value: F111: cold, Sample1: chr [1:4] "1.274e7" "" "" "2.301e7"
# ..$ Value: F111: warm, Sample1: chr [1:4] "" "" "" ""
# $ :'data.frame': 4 obs. of 3 variables:
# ..$ Abund216 : chr [1:4] "BROS" "TMS" "KIS" "HERS"
# ..$ Value: F216: cold, Sample2: chr [1:4] "1.670e6" "4.115e7" "" "1.302e7"
# ..$ Value: F216: warm, Sample2: chr [1:4] "" "2.766e7" "" "1.396e7"
# $ :'data.frame': 4 obs. of 3 variables:
# ..$ Abund655 : chr [1:4] "BROS" "TMS" "KIS" "HERS"
# ..$ Value: F655: cold, Sample3: chr [1:4] "7.074e4" "1.038e7" "" "7.380e5"
# ..$ Value: F655: warm, Sample3: chr [1:4] "" "6.874e6" "" "7.029e5"
This is both easier and harder. First, we attack the small problem:
otherfunc <- function(x, num) {
colnames(x)[1] <- paste0(colnames(x)[1], num)
x
}
Pretty straight forward. But we cannot use lapply
: all it does it accept a single argument, so it will not know what to do for the number. One might be tempted to brute-force things with a tracking variable somewhere (global? please no), but it might be interesting to know that there is a variant of the "apply" functions that operates differently: mapply
takes one or more lists, and "zips" them together. For example:
myfunc <- c
mapply(myfunc, 1:3, 4:6, 7:9, SIMPLIFY=FALSE)
# [[1]]
# [1] 1 4 7
# [[2]]
# [1] 2 5 8
# [[3]]
# [1] 3 6 9
We started with three (could have been more) independent vectors (could have been lists, typically are), and took the first value from each and passed them to the function. So this is effectively like:
list(myfunc(1, 4, 7), mufunc(2, 5, 8), myfunc(3, 6, 9))
Ok, so realizing that we want to "zip" together each frame with ltd
with a number along a sequence, those numbers are easily generated with:
seq_along(ltd)
# [1] 1 2 3
(This is considered better than 1:length(ltd)
, since the latter will not behave correctly if the length is 0 ... try 1:length(list())
versus seq_along(list())
.)
Okay, so let's use this new trick:
str(mapply(otherfunc, ltd, seq_along(ltd), SIMPLIFY=FALSE))
# List of 3
# $ :'data.frame': 4 obs. of 3 variables:
# ..$ Abund1 : chr [1:4] "BROS" "KIS" "TTHS" "MKS"
# ..$ Value: F111: cold, Sample1: chr [1:4] "1.274e7" "" "" "2.301e7"
# ..$ Value: F111: warm, Sample1: chr [1:4] "" "" "" ""
# $ :'data.frame': 4 obs. of 3 variables:
# ..$ Abund2 : chr [1:4] "BROS" "TMS" "KIS" "HERS"
# ..$ Value: F216: cold, Sample2: chr [1:4] "1.670e6" "4.115e7" "" "1.302e7"
# ..$ Value: F216: warm, Sample2: chr [1:4] "" "2.766e7" "" "1.396e7"
# $ :'data.frame': 4 obs. of 3 variables:
# ..$ Abund3 : chr [1:4] "BROS" "TMS" "KIS" "HERS"
# ..$ Value: F655: cold, Sample3: chr [1:4] "7.074e4" "1.038e7" "" "7.380e5"
# ..$ Value: F655: warm, Sample3: chr [1:4] "" "6.874e6" "" "7.029e5"
It should be noted that mapply
, just like sapply
, will by default try to simplify things; I find it hard to trust that it always do what I want, so I typically turn off this simplification. There are times for it, yes, here is not that time. The apply
functions (including Reduce
) are typically very hard to learn to use when thinking in a linear/iterative methodology, but they can be very useful in times like these.
Upvotes: 1