Reputation: 600
I have this data frame,
set.seed(124)
id <- rnorm(5, mean = 100, sd = 59)
charVar <- c("Eeny (2), meeny (10), miny (21), moe (1)",
"Catch (112), a (2), tiger (33), by (44), the (2), toe (24)",
NA,
"If (2), he (33), hollers (15), let (66), him (1), go (55)",
"Eeny (224), meeny (44), miny (50), moe (76)")
df <- data.frame(id, charVar)
df
> df
id charVar
1 18.28083 Eeny (2), meeny (10), miny (21), moe (1)
2 102.26107 Catch (112), a (2), tiger (33), by (44), the (2), toe (24)
3 54.98122 <NA>
4 112.52606 If (2), he (33), hollers (15), let (66), him (1), go (55)
5 184.10674 Eeny (224), meeny (44), miny (50), moe (76)
I want to sort every element in the rows by the numbers with it. The expected output should look like this:
> df
id charVar
1 18.28083 miny (21), meeny (10), Eeny (2), moe (1)
2 102.26107 Catch (112), by (44), tiger (33), toe (24), a (2), the (2)
3 54.98122 <NA>
4 112.52606 let (66), go (55), he (33), hollers (15), If (2), him (1)
5 184.10674 Eeny (224), moe (76), miny (50), meeny (44)
Any idea how to achive the expected result? Any help would be greatly appreciated.
Upvotes: 2
Views: 90
Reputation: 102529
With base R, you can try
transform(
df,
charVar = sapply(
strsplit(charVar, ", "),
\(x) toString(x[order(-as.integer(gsub("\\D+", "", x)))])
)
)
or you can use gtools::mixedsort
for simpler implementation
library(gtools)
df %>%
mutate(charVar = sapply(
strsplit(charVar, ", "),
\(x) toString(mixedsort(x, decreasing = TRUE))
))
which gives
id charVar
1 18.28083 miny (21), meeny (10), Eeny (2), moe (1)
2 102.26107 Catch (112), by (44), tiger (33), toe (24), a (2), the (2)
3 54.98122 NA
4 112.52606 let (66), go (55), he (33), hollers (15), If (2), him (1)
5 184.10674 Eeny (224), moe (76), miny (50), meeny (44)
Upvotes: 1
Reputation: 20494
As you've tagged tidyverse and data.table here are approaches using both.
tidyverse
approachEssentially we strsplit()
charVar
into a list-column where each element is a character vector, tidyr::unnest()
into long form, extract the numbers, then dplyr::summarise()
back into one row per id, where we paste()
back together the values in decreasing order()
:
library(dplyr)
df |>
mutate(charVar = strsplit(charVar, ", ")) |>
tidyr::unnest(charVar) |>
mutate(n = as.integer(gsub("\\D+", "", charVar))) |>
summarise(
charVar = paste(charVar[order(-n)], collapse = ", "),
.by = id
)
# id charVar
# 1 18.28083 miny (21), meeny (10), Eeny (2), moe (1)
# 2 102.26107 Catch (112), by (44), tiger (33), toe (24), a (2), the (2)
# 3 54.98122 NA
# 4 112.52606 let (66), go (55), he (33), hollers (15), If (2), him (1)
# 5 184.10674 Eeny (224), moe (76), miny (50), meeny (44)
data.table
approachThere is no equivalent of tidyr::unnest()
. While the same results can be achieved with unlisting, here's an approach which feels more idiomatic, which modifies charVar
in place:
library(data.table)
setDT(df)
df[, charVar := lapply(charVar, \(x) {
parts <- unlist(strsplit(x, ", "))
n <- as.integer(gsub("\\D+", "", parts))
paste(parts[order(-n)], collapse = ", ")
})]
# id charVar
# <num> <list>
# 1: 18.28083 miny (21), meeny (10), Eeny (2), moe (1)
# 2: 102.26107 Catch (112), by (44), tiger (33), toe (24), a (2), the (2)
# 3: 54.98122 NA
# 4: 112.52606 let (66), go (55), he (33), hollers (15), If (2), him (1)
# 5: 184.10674 Eeny (224), moe (76), miny (50), meeny (44)
Upvotes: 4
Reputation: 56219
Looks like this is a follow up to your previous question. Instead of dealing with XY problem, avoid the problem from the start:
#example data
df <- data.frame(var_1 = c(10, 5, 6, 0),
var_2 = c(0, 0, 3, 0),
var_3 = c(2, 0, 9, 0))
#sort and collapse to string
df$resString <- apply(df, 1, function(x, y = x[ x != 0 ]){
ix <- order(y, decreasing = TRUE)
if(length(ix)) paste(paste0(names(y)[ ix ], " (", y[ ix ], ")"), collapse = ", ") else return(NA)
})
#sort and keep as list column
df$resList <- apply(df[, grep("^var", colnames(df), value = TRUE) ], 1,
function(i) sort(i[ i != 0 ], decreasing = TRUE))
#df
# var_1 var_2 var_3 resString resList
# 1 10 0 2 var_1 (10), var_3 (2) 10, 2
# 2 5 0 0 var_1 (5) 5
# 3 6 3 9 var_3 (9), var_1 (6), var_2 (3) 9, 6, 3
# 4 0 0 0 <NA>
Upvotes: 6