Search code examples
rtidyversespread

Merging and transforming two sets of data


I have two rather large data files which I need to merge into one, in the following way:

A  <- tibble(
    id=1:2,
    firstName=c("Alice", "Bob")
)

B  <- tibble(
    id=c(1,1,2),
    email=c("alice@wonder.land.com", "alice2@wonderland.com", "bob@builder.com")
)

desiredResult  <- tibble(
    id=1:2,
    firstName=c("Alice", "Bob"),
    email1=c("alice@wonderland.com", "bob@builder.com"),
    email2=c("alice2@wonderland.com", NA)
) 

How can this be done efficiently? I tried using spread() but did not succeed and could only hack together a bad solution:

notGood  <-
    inner_join(A, B, by = "id") %>%
    split(., .$id) %>%
    map_dfr(function(x) as.tibble(t(unlist(x)))) %>%
    replace(is.na(.), "") %>%
    unite(id, id1, id, sep = "") %>%
    unite(firstName, firstName1, firstName, sep = "") %>%
    unite(email, email1, email, sep = "") %>%
    select(id, firstName, matches("email"))

EDIT:

The suggested solutions work great, but how could I apply them to more than one column? Like in this example:

A  <- tibble(
    id=1:2,
    firstName=c("Alice", "Bob")
)

B  <- tibble(
    id=c(1,1,2),
    email=c("alice@wonder.land.com", "alice2@wonderland.com", "bob@builder.com"),
    phone=c("123", "456", "789")
)

desiredResult  <- tibble(
    id=1:2,
    firstName=c("Alice", "Bob"),
    email1=c("alice@wonderland.com", "bob@builder.com"),
    email2=c("alice2@wonderland.com", NA),
    phone1=c("123", "789"),
    phone2=c("456", NA)
)

Simply adding more column names to the suggested answers doesn't quite work:

A %>%
    left_join(B, by='id') %>%
    group_by(id)%>%
    mutate(rn=paste0('email',row_number())) %>%
    mutate(rn2=paste0('phone',row_number())) %>%
    spread(rn, email) %>%
    spread(rn2, phone)

Solution

  • Check this solution:

    B %>%
      group_by(id) %>%
      mutate(rn = paste0('email', row_number())) %>%
      spread(rn, email) %>%
      right_join(A) %>%
      select(id, firstName, everything())
    

    Answer to added question:

    A %>%
      left_join(
        B %>%
          gather(key, val, -id) %>%
          group_by(id, key) %>%
          mutate(key2 = paste0(key, row_number())) %>%
          ungroup() %>%
          select(-key) %>%
          spread(key2, val)
      )