Reputation: 150
I want to order my columns based on the string name and first none zero value in each column.
assuming I have the following data:
col1_A col2_A col1_B col2_B
0 0 0 0
0 2 0 4
3 12 1 1
I need to order them in a way that columns with names including '_A' are place before '_B' and then the column with the first none zero value comes first. The expected out put will be:
col2_A col1_A col1_B col2_B
0 0 0 0
2 0 4 0
12 3 1 1
Here is the sample data for replicating.
df = data.frame('col1_A'=c(0,0,3),'col2_A'=c(0,2,12),'col1_B'=c(0,0,1),'col2_B'=c(0,4,1))
UPDATE:
Colnames are just examples, and the only the last character is important! hence I changed them to this now to avoid confusion.
Upvotes: 2
Views: 70
Reputation: 389135
Here's another way using split.default
-
purrr::map_dfc(split.default(df, sub('.*_', '', names(df))), function(x) {
x[order(sapply(x, function(x) match(TRUE, x !=0)))]
})
# col2_A col1_A col2_B col1_B
#1 0 0 0 0
#2 2 0 4 0
#3 12 3 1 1
sub
keeps only the important last character in the output. We split the data accordingly.
sub('.*_', '', names(df))
#[1] "A" "A" "B" "B"
For each group (A
and B
) we extract the position of first non zero value (match(TRUE, x!= 0)
) and use order
to rearrange the dataframe. map_dfc
is used to combine the list of dataframes in one combined dataframe.
Upvotes: 2
Reputation: 3899
library(tidyverse)
df = data.frame('col1_A'=c(0,0,3),'col2_A'=c(0,2,12),'col3_B'=c(0,0,1),'col4_B'=c(0,4,1))
df %>%
imap_chr(~ str_c(str_extract(.y, "\\w$"),
which(.x != 0)[1])) %>%
enframe() %>%
arrange(value) %>%
{df[.$name]}
#> col2_A col1_A col4_B col3_B
#> 1 0 0 0 0
#> 2 2 0 4 0
#> 3 12 3 1 1
Created on 2021-09-06 by the reprex package (v2.0.1)
Upvotes: 2