Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rearrage string elements by the number attached with it in rows

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.

like image 755
JontroPothon Avatar asked Dec 21 '25 06:12

JontroPothon


2 Answers

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>   
like image 95
zx8754 Avatar answered Dec 24 '25 01:12

zx8754


As you've tagged tidyverse and data.table here are approaches using both.

tidyverse approach

Essentially 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 approach

There 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)
like image 28
SamR Avatar answered Dec 23 '25 23:12

SamR



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!