convert data frame of “missed” numbers into data frame of numbers “hit”





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







3















I have quite an specific doubt, but it should be easy to solve, I just cannot think how...



I have a simple data frame like this:



mydf <- data.frame(Shooter=1:3, Targets.missed=c(paste(sample(1:10,4),collapse=";"), paste(sample(1:10,5),collapse=";"), paste(sample(1:10,8),collapse=";")))
mydf
Shooter Targets.missed
1 1 3;8;4;7
2 2 10;1;5;7;4
3 3 5;9;4;10;8;1;6;7


This data frame tells me the Targets (from 1 to 10) that are missed by each Shooter.



I would like to obtain a different data frame that tells me, per Target, which Shooters made it.



The result would be:



Target   hit.by.Shooters
1 1
2 1;2;3
3 2;3
4 NA
5 1
6 1;2
7 NA
8 2
9 1;2
10 1









share|improve this question




















  • 1





    Let me Edit for target and shooter so it's easier to interpret

    – DaniCee
    Jan 3 at 7:42






  • 1





    Perhaps library(dplyr); mydf %>% separate_rows(misses) %>% group_by(Number = misses) %>% summarise(ID = paste(unique(ID), collapse=";"))

    – akrun
    Jan 3 at 7:45











  • See the edit just in case; mind that we are looking at opposite things... in the first data frame is targets missed, in the second I want to look at targets hit

    – DaniCee
    Jan 3 at 7:47




















3















I have quite an specific doubt, but it should be easy to solve, I just cannot think how...



I have a simple data frame like this:



mydf <- data.frame(Shooter=1:3, Targets.missed=c(paste(sample(1:10,4),collapse=";"), paste(sample(1:10,5),collapse=";"), paste(sample(1:10,8),collapse=";")))
mydf
Shooter Targets.missed
1 1 3;8;4;7
2 2 10;1;5;7;4
3 3 5;9;4;10;8;1;6;7


This data frame tells me the Targets (from 1 to 10) that are missed by each Shooter.



I would like to obtain a different data frame that tells me, per Target, which Shooters made it.



The result would be:



Target   hit.by.Shooters
1 1
2 1;2;3
3 2;3
4 NA
5 1
6 1;2
7 NA
8 2
9 1;2
10 1









share|improve this question




















  • 1





    Let me Edit for target and shooter so it's easier to interpret

    – DaniCee
    Jan 3 at 7:42






  • 1





    Perhaps library(dplyr); mydf %>% separate_rows(misses) %>% group_by(Number = misses) %>% summarise(ID = paste(unique(ID), collapse=";"))

    – akrun
    Jan 3 at 7:45











  • See the edit just in case; mind that we are looking at opposite things... in the first data frame is targets missed, in the second I want to look at targets hit

    – DaniCee
    Jan 3 at 7:47
















3












3








3








I have quite an specific doubt, but it should be easy to solve, I just cannot think how...



I have a simple data frame like this:



mydf <- data.frame(Shooter=1:3, Targets.missed=c(paste(sample(1:10,4),collapse=";"), paste(sample(1:10,5),collapse=";"), paste(sample(1:10,8),collapse=";")))
mydf
Shooter Targets.missed
1 1 3;8;4;7
2 2 10;1;5;7;4
3 3 5;9;4;10;8;1;6;7


This data frame tells me the Targets (from 1 to 10) that are missed by each Shooter.



I would like to obtain a different data frame that tells me, per Target, which Shooters made it.



The result would be:



Target   hit.by.Shooters
1 1
2 1;2;3
3 2;3
4 NA
5 1
6 1;2
7 NA
8 2
9 1;2
10 1









share|improve this question
















I have quite an specific doubt, but it should be easy to solve, I just cannot think how...



I have a simple data frame like this:



mydf <- data.frame(Shooter=1:3, Targets.missed=c(paste(sample(1:10,4),collapse=";"), paste(sample(1:10,5),collapse=";"), paste(sample(1:10,8),collapse=";")))
mydf
Shooter Targets.missed
1 1 3;8;4;7
2 2 10;1;5;7;4
3 3 5;9;4;10;8;1;6;7


This data frame tells me the Targets (from 1 to 10) that are missed by each Shooter.



I would like to obtain a different data frame that tells me, per Target, which Shooters made it.



The result would be:



Target   hit.by.Shooters
1 1
2 1;2;3
3 2;3
4 NA
5 1
6 1;2
7 NA
8 2
9 1;2
10 1






r dataframe






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 3 at 8:37









Ronak Shah

45.7k104267




45.7k104267










asked Jan 3 at 7:40









DaniCeeDaniCee

345929




345929








  • 1





    Let me Edit for target and shooter so it's easier to interpret

    – DaniCee
    Jan 3 at 7:42






  • 1





    Perhaps library(dplyr); mydf %>% separate_rows(misses) %>% group_by(Number = misses) %>% summarise(ID = paste(unique(ID), collapse=";"))

    – akrun
    Jan 3 at 7:45











  • See the edit just in case; mind that we are looking at opposite things... in the first data frame is targets missed, in the second I want to look at targets hit

    – DaniCee
    Jan 3 at 7:47
















  • 1





    Let me Edit for target and shooter so it's easier to interpret

    – DaniCee
    Jan 3 at 7:42






  • 1





    Perhaps library(dplyr); mydf %>% separate_rows(misses) %>% group_by(Number = misses) %>% summarise(ID = paste(unique(ID), collapse=";"))

    – akrun
    Jan 3 at 7:45











  • See the edit just in case; mind that we are looking at opposite things... in the first data frame is targets missed, in the second I want to look at targets hit

    – DaniCee
    Jan 3 at 7:47










1




1





Let me Edit for target and shooter so it's easier to interpret

– DaniCee
Jan 3 at 7:42





Let me Edit for target and shooter so it's easier to interpret

– DaniCee
Jan 3 at 7:42




1




1





Perhaps library(dplyr); mydf %>% separate_rows(misses) %>% group_by(Number = misses) %>% summarise(ID = paste(unique(ID), collapse=";"))

– akrun
Jan 3 at 7:45





Perhaps library(dplyr); mydf %>% separate_rows(misses) %>% group_by(Number = misses) %>% summarise(ID = paste(unique(ID), collapse=";"))

– akrun
Jan 3 at 7:45













See the edit just in case; mind that we are looking at opposite things... in the first data frame is targets missed, in the second I want to look at targets hit

– DaniCee
Jan 3 at 7:47







See the edit just in case; mind that we are looking at opposite things... in the first data frame is targets missed, in the second I want to look at targets hit

– DaniCee
Jan 3 at 7:47














3 Answers
3






active

oldest

votes


















4














We expand the data by splitting at the ; of the 'Targets.missed' into 'long' format, then grouped by 'Shooter', summarise with a list of numbers that are not in the 'Targets.missed' from 1:10, unnest the list column, grouped by 'Target', summarise by pasteing the unique 'Shooter' elements into a single string, and fill the missing elements from 1:10 with NA by using complete



library(tidyverse)
mydf %>%
separate_rows(Targets.missed) %>%
group_by(Shooter) %>%
summarise(Target = list(setdiff(1:10, Targets.missed))) %>%
unnest %>%
group_by(Target) %>%
summarise(hit.by.Shooters = paste(unique(Shooter), collapse=";")) %>%
complete(Target = 1:10)
# A tibble: 10 x 2
# Target hit.by.Shooters
# <int> <chr>
# 1 1 1
# 2 2 1;2;3
# 3 3 2;3
# 4 4 <NA>
# 5 5 1
# 6 6 1;2
# 7 7 <NA>
# 8 8 2
# 9 9 1;2
#10 10 1




Or another option is base R by splitting the 'Targets.missed' (assuming character class) into a list of vectors, loop through the list, get the values that are not in 1:10 (with setdiff), set the names of the list with the 'Shooter' column, stack the key/val list pairs into a two column data.frame, get the unique rows, aggregate by pasteing the 'ind' column grouped by 'values', merge with a full 'values' dataset from 1:10



out <-  aggregate(ind ~ values, 
unique(stack(setNames(lapply(strsplit(mydf$Targets.missed, ';'),
setdiff, x= 1:10), mydf$Shooter))), FUN = paste, collapse=";")
out1 <- merge(data.frame(values = 1:10), out, all.x = TRUE)


and change the column names if necessary



names(out1) <- c('Target', 'hit.by.Shooters')


data



mydf <- structure(list(Shooter = 1:3, Targets.missed = c("3;8;4;7", "10;1;5;7;4", 
"5;9;4;10;8;1;6;7")), class = "data.frame", row.names = c("1",
"2", "3"))





share|improve this answer

































    1














    Another tidyverse possibility. We first create dataframe with all possible combinations of Shooter and Targets and then remove rows which are present in mydf using anti_join, fill in the missing Targets by adding them as NA and finally summarise by Targets to get Shooters who actually hit the target.



    library(tidyverse)

    crossing(Shooter = unique(mydf$Shooter), Targets.missed = 1:10) %>%
    anti_join(mydf %>% separate_rows(Targets.missed) %>% mutate_all(as.numeric)) %>%
    complete(Targets.missed = 1:10) %>%
    group_by(Targets.missed) %>%
    summarise(hit.by.Shooters = paste0(Shooter, collapse = ";"))


    # Targets.missed hit.by.Shooters
    # <int> <chr>
    # 1 1 1;2
    # 2 2 1;2
    # 3 3 1
    # 4 4 1
    # 5 5 2
    # 6 6 1;3
    # 7 7 1;2
    # 8 8 2
    # 9 9 NA
    #10 10 3


    data



    set.seed(987)
    mydf <- data.frame(Shooter=1:3,
    Targets.missed=c(paste(sample(1:10,4),collapse=";"),
    paste(sample(1:10,5),collapse=";"), paste(sample(1:10,8),collapse=";")))





    share|improve this answer































      1














      data.table approach



      library( data.table )

      #vector with all possible targets
      targets.v <- 1:10
      #split the missed targets to a list
      missed.list <- strsplit( mydf$Targets.missed, ";")
      #inverse, to get all hit targets
      hit.list <- lapply( missed.list, function(x) as.data.table( targets.v[!targets.v %in% x] ) )
      #bind hit targets to data.table
      dt <- rbindlist( hit.list, idcol = "shooter" )
      #summarise (paste with collapse), and join on all possible targets
      dt[, .(hit.by.shooters = paste(shooter, collapse = ";")), by = .(target = V1)][data.table(target = targets.v), on = c("target")]
      # target hit.by.shooters
      # 1: 1 1
      # 2: 2 1;2;3
      # 3: 3 2;3
      # 4: 4 <NA>
      # 5: 5 1
      # 6: 6 1;2
      # 7: 7 <NA>
      # 8: 8 2
      # 9: 9 1;2
      # 10: 10 1





      share|improve this answer


























        Your Answer






        StackExchange.ifUsing("editor", function () {
        StackExchange.using("externalEditor", function () {
        StackExchange.using("snippets", function () {
        StackExchange.snippets.init();
        });
        });
        }, "code-snippets");

        StackExchange.ready(function() {
        var channelOptions = {
        tags: "".split(" "),
        id: "1"
        };
        initTagRenderer("".split(" "), "".split(" "), channelOptions);

        StackExchange.using("externalEditor", function() {
        // Have to fire editor after snippets, if snippets enabled
        if (StackExchange.settings.snippets.snippetsEnabled) {
        StackExchange.using("snippets", function() {
        createEditor();
        });
        }
        else {
        createEditor();
        }
        });

        function createEditor() {
        StackExchange.prepareEditor({
        heartbeatType: 'answer',
        autoActivateHeartbeat: false,
        convertImagesToLinks: true,
        noModals: true,
        showLowRepImageUploadWarning: true,
        reputationToPostImages: 10,
        bindNavPrevention: true,
        postfix: "",
        imageUploader: {
        brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
        contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
        allowUrls: true
        },
        onDemand: true,
        discardSelector: ".discard-answer"
        ,immediatelyShowMarkdownHelp:true
        });


        }
        });














        draft saved

        draft discarded


















        StackExchange.ready(
        function () {
        StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54018184%2fconvert-data-frame-of-missed-numbers-into-data-frame-of-numbers-hit%23new-answer', 'question_page');
        }
        );

        Post as a guest















        Required, but never shown

























        3 Answers
        3






        active

        oldest

        votes








        3 Answers
        3






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        4














        We expand the data by splitting at the ; of the 'Targets.missed' into 'long' format, then grouped by 'Shooter', summarise with a list of numbers that are not in the 'Targets.missed' from 1:10, unnest the list column, grouped by 'Target', summarise by pasteing the unique 'Shooter' elements into a single string, and fill the missing elements from 1:10 with NA by using complete



        library(tidyverse)
        mydf %>%
        separate_rows(Targets.missed) %>%
        group_by(Shooter) %>%
        summarise(Target = list(setdiff(1:10, Targets.missed))) %>%
        unnest %>%
        group_by(Target) %>%
        summarise(hit.by.Shooters = paste(unique(Shooter), collapse=";")) %>%
        complete(Target = 1:10)
        # A tibble: 10 x 2
        # Target hit.by.Shooters
        # <int> <chr>
        # 1 1 1
        # 2 2 1;2;3
        # 3 3 2;3
        # 4 4 <NA>
        # 5 5 1
        # 6 6 1;2
        # 7 7 <NA>
        # 8 8 2
        # 9 9 1;2
        #10 10 1




        Or another option is base R by splitting the 'Targets.missed' (assuming character class) into a list of vectors, loop through the list, get the values that are not in 1:10 (with setdiff), set the names of the list with the 'Shooter' column, stack the key/val list pairs into a two column data.frame, get the unique rows, aggregate by pasteing the 'ind' column grouped by 'values', merge with a full 'values' dataset from 1:10



        out <-  aggregate(ind ~ values, 
        unique(stack(setNames(lapply(strsplit(mydf$Targets.missed, ';'),
        setdiff, x= 1:10), mydf$Shooter))), FUN = paste, collapse=";")
        out1 <- merge(data.frame(values = 1:10), out, all.x = TRUE)


        and change the column names if necessary



        names(out1) <- c('Target', 'hit.by.Shooters')


        data



        mydf <- structure(list(Shooter = 1:3, Targets.missed = c("3;8;4;7", "10;1;5;7;4", 
        "5;9;4;10;8;1;6;7")), class = "data.frame", row.names = c("1",
        "2", "3"))





        share|improve this answer






























          4














          We expand the data by splitting at the ; of the 'Targets.missed' into 'long' format, then grouped by 'Shooter', summarise with a list of numbers that are not in the 'Targets.missed' from 1:10, unnest the list column, grouped by 'Target', summarise by pasteing the unique 'Shooter' elements into a single string, and fill the missing elements from 1:10 with NA by using complete



          library(tidyverse)
          mydf %>%
          separate_rows(Targets.missed) %>%
          group_by(Shooter) %>%
          summarise(Target = list(setdiff(1:10, Targets.missed))) %>%
          unnest %>%
          group_by(Target) %>%
          summarise(hit.by.Shooters = paste(unique(Shooter), collapse=";")) %>%
          complete(Target = 1:10)
          # A tibble: 10 x 2
          # Target hit.by.Shooters
          # <int> <chr>
          # 1 1 1
          # 2 2 1;2;3
          # 3 3 2;3
          # 4 4 <NA>
          # 5 5 1
          # 6 6 1;2
          # 7 7 <NA>
          # 8 8 2
          # 9 9 1;2
          #10 10 1




          Or another option is base R by splitting the 'Targets.missed' (assuming character class) into a list of vectors, loop through the list, get the values that are not in 1:10 (with setdiff), set the names of the list with the 'Shooter' column, stack the key/val list pairs into a two column data.frame, get the unique rows, aggregate by pasteing the 'ind' column grouped by 'values', merge with a full 'values' dataset from 1:10



          out <-  aggregate(ind ~ values, 
          unique(stack(setNames(lapply(strsplit(mydf$Targets.missed, ';'),
          setdiff, x= 1:10), mydf$Shooter))), FUN = paste, collapse=";")
          out1 <- merge(data.frame(values = 1:10), out, all.x = TRUE)


          and change the column names if necessary



          names(out1) <- c('Target', 'hit.by.Shooters')


          data



          mydf <- structure(list(Shooter = 1:3, Targets.missed = c("3;8;4;7", "10;1;5;7;4", 
          "5;9;4;10;8;1;6;7")), class = "data.frame", row.names = c("1",
          "2", "3"))





          share|improve this answer




























            4












            4








            4







            We expand the data by splitting at the ; of the 'Targets.missed' into 'long' format, then grouped by 'Shooter', summarise with a list of numbers that are not in the 'Targets.missed' from 1:10, unnest the list column, grouped by 'Target', summarise by pasteing the unique 'Shooter' elements into a single string, and fill the missing elements from 1:10 with NA by using complete



            library(tidyverse)
            mydf %>%
            separate_rows(Targets.missed) %>%
            group_by(Shooter) %>%
            summarise(Target = list(setdiff(1:10, Targets.missed))) %>%
            unnest %>%
            group_by(Target) %>%
            summarise(hit.by.Shooters = paste(unique(Shooter), collapse=";")) %>%
            complete(Target = 1:10)
            # A tibble: 10 x 2
            # Target hit.by.Shooters
            # <int> <chr>
            # 1 1 1
            # 2 2 1;2;3
            # 3 3 2;3
            # 4 4 <NA>
            # 5 5 1
            # 6 6 1;2
            # 7 7 <NA>
            # 8 8 2
            # 9 9 1;2
            #10 10 1




            Or another option is base R by splitting the 'Targets.missed' (assuming character class) into a list of vectors, loop through the list, get the values that are not in 1:10 (with setdiff), set the names of the list with the 'Shooter' column, stack the key/val list pairs into a two column data.frame, get the unique rows, aggregate by pasteing the 'ind' column grouped by 'values', merge with a full 'values' dataset from 1:10



            out <-  aggregate(ind ~ values, 
            unique(stack(setNames(lapply(strsplit(mydf$Targets.missed, ';'),
            setdiff, x= 1:10), mydf$Shooter))), FUN = paste, collapse=";")
            out1 <- merge(data.frame(values = 1:10), out, all.x = TRUE)


            and change the column names if necessary



            names(out1) <- c('Target', 'hit.by.Shooters')


            data



            mydf <- structure(list(Shooter = 1:3, Targets.missed = c("3;8;4;7", "10;1;5;7;4", 
            "5;9;4;10;8;1;6;7")), class = "data.frame", row.names = c("1",
            "2", "3"))





            share|improve this answer















            We expand the data by splitting at the ; of the 'Targets.missed' into 'long' format, then grouped by 'Shooter', summarise with a list of numbers that are not in the 'Targets.missed' from 1:10, unnest the list column, grouped by 'Target', summarise by pasteing the unique 'Shooter' elements into a single string, and fill the missing elements from 1:10 with NA by using complete



            library(tidyverse)
            mydf %>%
            separate_rows(Targets.missed) %>%
            group_by(Shooter) %>%
            summarise(Target = list(setdiff(1:10, Targets.missed))) %>%
            unnest %>%
            group_by(Target) %>%
            summarise(hit.by.Shooters = paste(unique(Shooter), collapse=";")) %>%
            complete(Target = 1:10)
            # A tibble: 10 x 2
            # Target hit.by.Shooters
            # <int> <chr>
            # 1 1 1
            # 2 2 1;2;3
            # 3 3 2;3
            # 4 4 <NA>
            # 5 5 1
            # 6 6 1;2
            # 7 7 <NA>
            # 8 8 2
            # 9 9 1;2
            #10 10 1




            Or another option is base R by splitting the 'Targets.missed' (assuming character class) into a list of vectors, loop through the list, get the values that are not in 1:10 (with setdiff), set the names of the list with the 'Shooter' column, stack the key/val list pairs into a two column data.frame, get the unique rows, aggregate by pasteing the 'ind' column grouped by 'values', merge with a full 'values' dataset from 1:10



            out <-  aggregate(ind ~ values, 
            unique(stack(setNames(lapply(strsplit(mydf$Targets.missed, ';'),
            setdiff, x= 1:10), mydf$Shooter))), FUN = paste, collapse=";")
            out1 <- merge(data.frame(values = 1:10), out, all.x = TRUE)


            and change the column names if necessary



            names(out1) <- c('Target', 'hit.by.Shooters')


            data



            mydf <- structure(list(Shooter = 1:3, Targets.missed = c("3;8;4;7", "10;1;5;7;4", 
            "5;9;4;10;8;1;6;7")), class = "data.frame", row.names = c("1",
            "2", "3"))






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jan 3 at 8:07

























            answered Jan 3 at 7:54









            akrunakrun

            420k13208284




            420k13208284

























                1














                Another tidyverse possibility. We first create dataframe with all possible combinations of Shooter and Targets and then remove rows which are present in mydf using anti_join, fill in the missing Targets by adding them as NA and finally summarise by Targets to get Shooters who actually hit the target.



                library(tidyverse)

                crossing(Shooter = unique(mydf$Shooter), Targets.missed = 1:10) %>%
                anti_join(mydf %>% separate_rows(Targets.missed) %>% mutate_all(as.numeric)) %>%
                complete(Targets.missed = 1:10) %>%
                group_by(Targets.missed) %>%
                summarise(hit.by.Shooters = paste0(Shooter, collapse = ";"))


                # Targets.missed hit.by.Shooters
                # <int> <chr>
                # 1 1 1;2
                # 2 2 1;2
                # 3 3 1
                # 4 4 1
                # 5 5 2
                # 6 6 1;3
                # 7 7 1;2
                # 8 8 2
                # 9 9 NA
                #10 10 3


                data



                set.seed(987)
                mydf <- data.frame(Shooter=1:3,
                Targets.missed=c(paste(sample(1:10,4),collapse=";"),
                paste(sample(1:10,5),collapse=";"), paste(sample(1:10,8),collapse=";")))





                share|improve this answer




























                  1














                  Another tidyverse possibility. We first create dataframe with all possible combinations of Shooter and Targets and then remove rows which are present in mydf using anti_join, fill in the missing Targets by adding them as NA and finally summarise by Targets to get Shooters who actually hit the target.



                  library(tidyverse)

                  crossing(Shooter = unique(mydf$Shooter), Targets.missed = 1:10) %>%
                  anti_join(mydf %>% separate_rows(Targets.missed) %>% mutate_all(as.numeric)) %>%
                  complete(Targets.missed = 1:10) %>%
                  group_by(Targets.missed) %>%
                  summarise(hit.by.Shooters = paste0(Shooter, collapse = ";"))


                  # Targets.missed hit.by.Shooters
                  # <int> <chr>
                  # 1 1 1;2
                  # 2 2 1;2
                  # 3 3 1
                  # 4 4 1
                  # 5 5 2
                  # 6 6 1;3
                  # 7 7 1;2
                  # 8 8 2
                  # 9 9 NA
                  #10 10 3


                  data



                  set.seed(987)
                  mydf <- data.frame(Shooter=1:3,
                  Targets.missed=c(paste(sample(1:10,4),collapse=";"),
                  paste(sample(1:10,5),collapse=";"), paste(sample(1:10,8),collapse=";")))





                  share|improve this answer


























                    1












                    1








                    1







                    Another tidyverse possibility. We first create dataframe with all possible combinations of Shooter and Targets and then remove rows which are present in mydf using anti_join, fill in the missing Targets by adding them as NA and finally summarise by Targets to get Shooters who actually hit the target.



                    library(tidyverse)

                    crossing(Shooter = unique(mydf$Shooter), Targets.missed = 1:10) %>%
                    anti_join(mydf %>% separate_rows(Targets.missed) %>% mutate_all(as.numeric)) %>%
                    complete(Targets.missed = 1:10) %>%
                    group_by(Targets.missed) %>%
                    summarise(hit.by.Shooters = paste0(Shooter, collapse = ";"))


                    # Targets.missed hit.by.Shooters
                    # <int> <chr>
                    # 1 1 1;2
                    # 2 2 1;2
                    # 3 3 1
                    # 4 4 1
                    # 5 5 2
                    # 6 6 1;3
                    # 7 7 1;2
                    # 8 8 2
                    # 9 9 NA
                    #10 10 3


                    data



                    set.seed(987)
                    mydf <- data.frame(Shooter=1:3,
                    Targets.missed=c(paste(sample(1:10,4),collapse=";"),
                    paste(sample(1:10,5),collapse=";"), paste(sample(1:10,8),collapse=";")))





                    share|improve this answer













                    Another tidyverse possibility. We first create dataframe with all possible combinations of Shooter and Targets and then remove rows which are present in mydf using anti_join, fill in the missing Targets by adding them as NA and finally summarise by Targets to get Shooters who actually hit the target.



                    library(tidyverse)

                    crossing(Shooter = unique(mydf$Shooter), Targets.missed = 1:10) %>%
                    anti_join(mydf %>% separate_rows(Targets.missed) %>% mutate_all(as.numeric)) %>%
                    complete(Targets.missed = 1:10) %>%
                    group_by(Targets.missed) %>%
                    summarise(hit.by.Shooters = paste0(Shooter, collapse = ";"))


                    # Targets.missed hit.by.Shooters
                    # <int> <chr>
                    # 1 1 1;2
                    # 2 2 1;2
                    # 3 3 1
                    # 4 4 1
                    # 5 5 2
                    # 6 6 1;3
                    # 7 7 1;2
                    # 8 8 2
                    # 9 9 NA
                    #10 10 3


                    data



                    set.seed(987)
                    mydf <- data.frame(Shooter=1:3,
                    Targets.missed=c(paste(sample(1:10,4),collapse=";"),
                    paste(sample(1:10,5),collapse=";"), paste(sample(1:10,8),collapse=";")))






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Jan 3 at 8:27









                    Ronak ShahRonak Shah

                    45.7k104267




                    45.7k104267























                        1














                        data.table approach



                        library( data.table )

                        #vector with all possible targets
                        targets.v <- 1:10
                        #split the missed targets to a list
                        missed.list <- strsplit( mydf$Targets.missed, ";")
                        #inverse, to get all hit targets
                        hit.list <- lapply( missed.list, function(x) as.data.table( targets.v[!targets.v %in% x] ) )
                        #bind hit targets to data.table
                        dt <- rbindlist( hit.list, idcol = "shooter" )
                        #summarise (paste with collapse), and join on all possible targets
                        dt[, .(hit.by.shooters = paste(shooter, collapse = ";")), by = .(target = V1)][data.table(target = targets.v), on = c("target")]
                        # target hit.by.shooters
                        # 1: 1 1
                        # 2: 2 1;2;3
                        # 3: 3 2;3
                        # 4: 4 <NA>
                        # 5: 5 1
                        # 6: 6 1;2
                        # 7: 7 <NA>
                        # 8: 8 2
                        # 9: 9 1;2
                        # 10: 10 1





                        share|improve this answer






























                          1














                          data.table approach



                          library( data.table )

                          #vector with all possible targets
                          targets.v <- 1:10
                          #split the missed targets to a list
                          missed.list <- strsplit( mydf$Targets.missed, ";")
                          #inverse, to get all hit targets
                          hit.list <- lapply( missed.list, function(x) as.data.table( targets.v[!targets.v %in% x] ) )
                          #bind hit targets to data.table
                          dt <- rbindlist( hit.list, idcol = "shooter" )
                          #summarise (paste with collapse), and join on all possible targets
                          dt[, .(hit.by.shooters = paste(shooter, collapse = ";")), by = .(target = V1)][data.table(target = targets.v), on = c("target")]
                          # target hit.by.shooters
                          # 1: 1 1
                          # 2: 2 1;2;3
                          # 3: 3 2;3
                          # 4: 4 <NA>
                          # 5: 5 1
                          # 6: 6 1;2
                          # 7: 7 <NA>
                          # 8: 8 2
                          # 9: 9 1;2
                          # 10: 10 1





                          share|improve this answer




























                            1












                            1








                            1







                            data.table approach



                            library( data.table )

                            #vector with all possible targets
                            targets.v <- 1:10
                            #split the missed targets to a list
                            missed.list <- strsplit( mydf$Targets.missed, ";")
                            #inverse, to get all hit targets
                            hit.list <- lapply( missed.list, function(x) as.data.table( targets.v[!targets.v %in% x] ) )
                            #bind hit targets to data.table
                            dt <- rbindlist( hit.list, idcol = "shooter" )
                            #summarise (paste with collapse), and join on all possible targets
                            dt[, .(hit.by.shooters = paste(shooter, collapse = ";")), by = .(target = V1)][data.table(target = targets.v), on = c("target")]
                            # target hit.by.shooters
                            # 1: 1 1
                            # 2: 2 1;2;3
                            # 3: 3 2;3
                            # 4: 4 <NA>
                            # 5: 5 1
                            # 6: 6 1;2
                            # 7: 7 <NA>
                            # 8: 8 2
                            # 9: 9 1;2
                            # 10: 10 1





                            share|improve this answer















                            data.table approach



                            library( data.table )

                            #vector with all possible targets
                            targets.v <- 1:10
                            #split the missed targets to a list
                            missed.list <- strsplit( mydf$Targets.missed, ";")
                            #inverse, to get all hit targets
                            hit.list <- lapply( missed.list, function(x) as.data.table( targets.v[!targets.v %in% x] ) )
                            #bind hit targets to data.table
                            dt <- rbindlist( hit.list, idcol = "shooter" )
                            #summarise (paste with collapse), and join on all possible targets
                            dt[, .(hit.by.shooters = paste(shooter, collapse = ";")), by = .(target = V1)][data.table(target = targets.v), on = c("target")]
                            # target hit.by.shooters
                            # 1: 1 1
                            # 2: 2 1;2;3
                            # 3: 3 2;3
                            # 4: 4 <NA>
                            # 5: 5 1
                            # 6: 6 1;2
                            # 7: 7 <NA>
                            # 8: 8 2
                            # 9: 9 1;2
                            # 10: 10 1






                            share|improve this answer














                            share|improve this answer



                            share|improve this answer








                            edited Jan 3 at 8:30

























                            answered Jan 3 at 8:24









                            WimpelWimpel

                            6,347323




                            6,347323






























                                draft saved

                                draft discarded




















































                                Thanks for contributing an answer to Stack Overflow!


                                • Please be sure to answer the question. Provide details and share your research!

                                But avoid



                                • Asking for help, clarification, or responding to other answers.

                                • Making statements based on opinion; back them up with references or personal experience.


                                To learn more, see our tips on writing great answers.




                                draft saved


                                draft discarded














                                StackExchange.ready(
                                function () {
                                StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54018184%2fconvert-data-frame-of-missed-numbers-into-data-frame-of-numbers-hit%23new-answer', 'question_page');
                                }
                                );

                                Post as a guest















                                Required, but never shown





















































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown

































                                Required, but never shown














                                Required, but never shown












                                Required, but never shown







                                Required, but never shown







                                Popular posts from this blog

                                MongoDB - Not Authorized To Execute Command

                                How to fix TextFormField cause rebuild widget in Flutter

                                in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith