Search code examples
rdataframeorg-mode

R map org headlines to dataframe


I have a simple org file as follows:

* Title
** Book 1
*** Chapter 1
*** Chapter 2
...
** Book 3
...

I would like to map the above headline structure to a dataframe so that each chapter can be related to its corresponding book and title as follows:

data.frame(title="Title", bk=c("Book 1", "Book 1", "Book 3"), ch=c("Chapter 1", "Chapter 2", "Chapter 1"))

  title     bk        ch
1 Title Book 1 Chapter 1
2 Title Book 1 Chapter 2
...
32 Title Book 3 Chapter 1

The depth of each headline can be indexed with this code:

headlines=grep('\\*', input, value=T)
id=str_count(headlines, "\\*")

So that the following would give me separate vectors for books and chapters (title is pretty straightforward, in this case):

ch=headlines[id==3]
bk=headlines[id==2]

As we can see, the ch vector would definitely be longer than the bk. Using id as a reference, how do we get bk to repeat correspondingly so that they can be bound together to form the dataframe above?

Other approaches are also welcome.


The Actual Data

Following is the actual data, corresponding to books and chapters in the Analects. For those who cannot read Chinese, a single * is the title of the whole (collection of) book(s), ** is the individual books, *** is the chapters.

headlines=
c("* 論語", "** 學而第一", "*** 第1章", "*** 第2章", 
"*** 第3章", "*** 第4章", "*** 第5章", "*** 第6章", "*** 第7章", 
"*** 第8章", "*** 第9章", "*** 第10章", "*** 第11章", 
"*** 第12章", "*** 第13章", "*** 第14章", "*** 第15章", 
"*** 第16章", "** 為政第二", "*** 第1章", "*** 第2章", 
"*** 第3章", "*** 第4章", "*** 第5章", "*** 第6章", "*** 第7章", 
"*** 第8章", "*** 第9章", "*** 第10章", "*** 第11章", 
"*** 第12章", "*** 第13章", "*** 第14章", "*** 第15章", 
"*** 第16章", "*** 第17章", "*** 第18章", "*** 第19章", 
"*** 第20章", "*** 第21章", "*** 第22章", "*** 第23章", 
"*** 第24章", "** 八佾第三", "*** 第1章", "*** 第2章", 
"*** 第3章", "*** 第4章", "*** 第5章", "*** 第6章", "*** 第7章", 
"*** 第8章", "*** 第9章", "*** 第10章", "*** 第11章", 
"*** 第12章", "*** 第13章", "*** 第14章", "*** 第15章", 
"*** 第16章", "*** 第17章", "*** 第18章", "*** 第19章", 
"*** 第20章", "*** 第21章", "*** 第22章", "*** 第23章", 
"*** 第24章", "*** 第25章", "*** 第26章", "** 里仁第四", 
"*** 第1章", "*** 第2章", "*** 第3章", "*** 第4章", "*** 第5章", 
"*** 第6章", "*** 第7章", "*** 第8章", "*** 第9章", "*** 第10章", 
"*** 第11章", "*** 第12章", "*** 第13章", "*** 第14章", 
"*** 第15章", "*** 第16章", "*** 第17章", "*** 第18章", 
"*** 第19章", "*** 第20章", "*** 第21章", "*** 第22章", 
"*** 第23章", "*** 第24章", "*** 第25章", "*** 第26章", 
"** 公冶長第五", "*** 第1章", "*** 第2章", "*** 第3章", 
"*** 第4章", "*** 第5章", "*** 第6章", "*** 第7章", "*** 第8章", 
"*** 第9章", "*** 第10章", "*** 第11章", "*** 第12章", 
"*** 第13章", "*** 第14章", "*** 第15章", "*** 第16章", 
"*** 第17章", "*** 第18章", "*** 第19章", "*** 第20章", 
"*** 第21章", "*** 第22章", "*** 第23章", "*** 第24章", 
"*** 第25章", "*** 第26章", "*** 第27章", "*** 第28章", 
"** 雍也第六", "*** 第1章", "*** 第2章", "*** 第3章", 
"*** 第4章", "*** 第5章", "*** 第6章", "*** 第7章", "*** 第8章", 
"*** 第9章", "*** 第10章", "*** 第11章", "*** 第12章", 
"*** 第13章", "*** 第14章", "*** 第15章", "*** 第16章", 
"*** 第17章", "*** 第18章", "*** 第19章", "*** 第20章", 
"*** 第21章", "*** 第22章", "*** 第23章", "*** 第24章", 
"*** 第25章", "*** 第26章", "*** 第27章", "*** 第28章", 
"** 述而第七", "*** 第1章", "*** 第2章", "*** 第3章", 
"*** 第4章", "*** 第5章", "*** 第6章", "*** 第7章", "*** 第8章", 
"*** 第9章", "*** 第10章", "*** 第11章", "*** 第12章", 
"*** 第13章", "*** 第14章", "*** 第15章", "*** 第16章", 
"*** 第17章", "*** 第18章", "*** 第19章", "*** 第20章", 
"*** 第21章", "*** 第22章", "*** 第23章", "*** 第24章", 
"*** 第26章", "*** 第27章", "*** 第28章", "*** 第29章", 
"*** 第30章", "*** 第31章", "*** 第32章", "*** 第33章", 
"*** 第34章", "*** 第35章", "*** 第36章", "*** 第37章", 
"*** 第38章", "** 泰伯第八", "*** 第1章", "*** 第2章", 
"*** 第3章", "*** 第4章", "*** 第5章", "*** 第6章", "*** 第7章", 
"*** 第8章", "*** 第9章", "*** 第10章", "*** 第11章", 
"*** 第12章", "*** 第13章", "*** 第14章", "*** 第15章", 
"*** 第16章", "*** 第17章", "*** 第18章", "*** 第19章", 
"*** 第20章", "*** 第21章", "** 子罕第九", "*** 第1章", 
"*** 第2章", "*** 第3章", "*** 第4章", "*** 第5章", "*** 第6章", 
"*** 第7章", "*** 第8章", "*** 第9章", "*** 第10章", 
"*** 第11章", "*** 第12章", "*** 第13章", "*** 第14章", 
"*** 第15章", "*** 第16章", "*** 第17章", "*** 第18章", 
"*** 第19章", "*** 第20章", "*** 第21章", "*** 第22章", 
"*** 第23章", "*** 第24章", "*** 第25章", "*** 第26章", 
"*** 第27章", "*** 第28章", "*** 第29章", "*** 第30章", 
"** 鄉黨第十", "*** 第1章", "*** 第3章", "*** 第4章", 
"*** 第5章", "*** 第6章", "*** 第7章", "*** 第8章", "*** 第9章", 
"*** 第10章", "*** 第11章", "*** 第12章", "*** 第13章", 
"*** 第14章", "*** 第15章", "*** 第16章", "*** 第17章", 
"*** 第18章", "** 先進第十一", "*** 第1章", "*** 第2章", 
"*** 第3章", "*** 第4章", "*** 第5章", "*** 第6章", "*** 第7章", 
"*** 第8章", "*** 第9章", "*** 第10章", "*** 第11章", 
"*** 第12章", "*** 第13章", "*** 第14章", "*** 第15章", 
"*** 第16章", "*** 第17章", "*** 第19章", "*** 第21章", 
"*** 第21章", "*** 第22章", "*** 第23章", "*** 第24章", 
"** 顏淵第十二", "*** 第1章", "*** 第3章", "*** 第4章", 
"*** 第5章", "*** 第5章", "*** 第6章", "*** 第7章", "*** 第8章", 
"*** 第9章", "*** 第10章", "*** 第11章", "*** 第12章", 
"*** 第13章", "*** 第14章", "*** 第15章", "*** 第16章", 
"*** 第17章", "*** 第18章", "*** 第19章", "*** 第20章", 
"*** 第21章", "*** 第22章", "*** 第23章", "*** 第24章", 
"** 子路第十三", "*** 第1章", "*** 第2章", "*** 第3章", 
"*** 第4章", "*** 第5章", "*** 第6章", "*** 第7章", "*** 第8章", 
"*** 第9章", "*** 第10章", "*** 第11章", "*** 第12章", 
"*** 第13章", "*** 第14章", "*** 第15章", "*** 第16章", 
"*** 第17章", "*** 第18章", "*** 第19章", "*** 第20章", 
"*** 第21章", "*** 第22章", "*** 第23章", "*** 第24章", 
"*** 第25章", "*** 第26章", "*** 第27章", "*** 第28章", 
"*** 第29章", "*** 第30章", "** 憲問第十四", "*** 第1章", 
"*** 第3章", "*** 第4章", "*** 第5章", "*** 第6章", "*** 第7章", 
"*** 第8章", "*** 第9章", "*** 第10章", "*** 第11章", 
"*** 第12章", "*** 第13章", "*** 第14章", "*** 第15章", 
"*** 第16章", "*** 第17章", "*** 第18章", "*** 第19章", 
"*** 第20章", "*** 第21章", "*** 第22章", "*** 第23章", 
"*** 第24章", "*** 第25章", "*** 第26章", "*** 第27章", 
"*** 第28章", "*** 第29章", "*** 第30章", "*** 第31章", 
"*** 第32章", "*** 第33章", "*** 第34章", "*** 第35章", 
"*** 第36章", "*** 第37章", "*** 第38章", "*** 第39章", 
"*** 第41章", "*** 第42章", "*** 第43章", "*** 第44章", 
"*** 第45章", "*** 第46章", "*** 第47章", "** 衛靈公第十五", 
"*** 第1章", "*** 第3章", "*** 第4章", "*** 第5章", "*** 第6章", 
"*** 第7章", "*** 第8章", "*** 第9章", "*** 第10章", 
"*** 第11章", "*** 第12章", "*** 第13章", "*** 第14章", 
"*** 第15章", "*** 第16章", "*** 第17章", "*** 第18章", 
"*** 第19章", "*** 第20章", "*** 第21章", "*** 第22章", 
"*** 第23章", "*** 第24章", "*** 第25章", "*** 第26章", 
"*** 第27章", "*** 第28章", "*** 第29章", "*** 第30章", 
"*** 第31章", "*** 第32章", "*** 第33章", "*** 第34章", 
"*** 第35章", "*** 第36章", "*** 第37章", "*** 第38章", 
"*** 第39章", "*** 第40章", "*** 第41章", "*** 第42章", 
"** 季氏第十六", "*** 第1章", "*** 第2章", "*** 第3章", 
"*** 第4章", "*** 第5章", "*** 第6章", "*** 第7章", "*** 第8章", 
"*** 第9章", "*** 第10章", "*** 第11章", "*** 第12章", 
"*** 第13章", "*** 第14章", "** 陽貨第十七", "*** 第1章", 
"*** 第2章", "*** 第3章", "*** 第4章", "*** 第5章", "*** 第6章", 
"*** 第7章", "*** 第8章", "*** 第9章", "*** 第10章", 
"*** 第11章", "*** 第12章", "*** 第13章", "*** 第14章", 
"*** 第15章", "*** 第16章", "*** 第17章", "*** 第18章", 
"*** 第19章", "*** 第20章", "*** 第21章", "*** 第22章", 
"*** 第23章", "*** 第24章", "** 微子第十八", "*** 第1章", 
"*** 第2章", "*** 第3章", "*** 第4章", "*** 第5章", "*** 第6章", 
"*** 第7章", "*** 第8章", "*** 第9章", "*** 第10章", 
"*** 第11章", "** 子張第十九", "*** 第1章", "*** 第2章", 
"*** 第3章", "*** 第4章", "*** 第5章", "*** 第6章", "*** 第7章", 
"*** 第8章", "*** 第9章", "*** 第10章", "*** 第11章", 
"*** 第12章", "*** 第13章", "*** 第14章", "*** 第15章", 
"*** 第16章", "*** 第17章", "*** 第18章", "*** 第19章", 
"*** 第20章", "*** 第21章", "*** 第22章", "*** 第23章", 
"*** 第24章", "*** 第25章", "** 堯曰第二十", "*** 第1章", 
"*** 第2章", "*** 第3章")

So I am looking for something like this:

   title          bk        ch
1 * 論語 ** 學而第一 *** 第1章
2 * 論語 ** 學而第一 *** 第2章
...
41 * 論語 ** 八佾第三 *** 第1章

Solution

  • Several methods are possible. One method:

    library(tidyr)
    library(dplyr)
    headlines <- c("Book 1", "Chapter 1", "Chapter 2", "Book 2", "Chapter 1", "Chapter 2")
    id        <- c(1, 2, 2, 1, 2, 2)
    
    df <- data.frame(ID=id, Book=headlines, Chapter=headlines)
    df %>% mutate(Book=ifelse(id == 1, Book, NA)) %>% fill(Book) %>% filter(id == 2)
    

    Without using tidyverse:

    books <- headlines[ id == 1 ]
    chapters <- headlines[ id == 2 ]
    rl <- rle(id)
    reps <- rl$lengths[ rl$values == 2 ]
    books <- unlist(lapply(1:length(books), function(i) rep(books[i], reps[i])))
    df <- data.frame(Books=books, Chapters=chapters)