Related
I have 2 tables
First tabel name is "consumer"
id_consumer
name
1
Roy
2
Dori
3
Rico
Second tabel name is "consumer_address"
id_consumer
address
status
1
Street Avenue
1
1
Park Hill
0
2
Highwalk Street
1
2
Albion Place
0
Condition
name from tabel "consumer"
address from "consumer_address" , but i want to get only 1 address when consumer_address.status = 1
When Consumer not have data in tabel "consumer_address", field is NULL
The Final Tabel Like this
id_consumer
name
address
status
1
Roy
Street Avenue
1
2
Dori
Highwalk Street
1
3
Rico
NULL
NULL
i have query, but its not work
this is my query
SELECT
id_consumer,
name,
CASE WHEN (`consumer_address`.`status` = 1) THEN `consumer_address`.`address` ELSE NULL END as "Address",
CASE WHEN (`consumer_address`.`status` = 1) THEN `consumer_address`.`status` ELSE NULL END as "Status"
FROM consumer
JOIN consumer_address ON consumer_address.id_consumer = consumer.id_consumer
Thanks
Very simple solution:
SELECT
`id_consumer`,
`name`,
`consumer_address`.`address`,
`consumer_address`.`status`
FROM consumer
LEFT JOIN consumer_address ON
`consumer_address`.`id_consumer` = `consumer`.`id_consumer` AND
`consumer_address`.`status` = 1
Instead of using CASE WHEN just include the status in the JOIN.
Additionally, to keep consumer 3, you need a LEFT JOIN.
SELECT
id_consumer,
name,
`consumer_address`.`address`,
`consumer_address`.`status`
FROM
consumer
LEFT JOIN
consumer_address
ON consumer_address.id_consumer = consumer.id_consumer
AND consumer_address.status = 1
I have the following data:
transaction <- c(1,2,3);
date <- c("2010-01-31","2010-02-28","2010-03-31");
type <- c("debit", "debit", "credit");
amount <- c(-500, -1000.97, 12500.81);
oldbalance <- c(5000, 4500, 17000.81)
evolution <- data.frame(transaction, date, type, amount, oldbalance, row.names=transaction, stringsAsFactors=FALSE);
evolution <- transform(evolution, newbalance = oldbalance + amount);
evolution
Running
> library(xtable)
> xtable(evolution)
works fine. But if I add the line
evolution$date <- as.Date(evolution$date, "%Y-%m-%d");
to give
transaction <- c(1,2,3);
date <- c("2010-01-31","2010-02-28","2010-03-31");
type <- c("debit", "debit", "credit");
amount <- c(-500, -1000.97, 12500.81);
oldbalance <- c(5000, 4500, 17000.81)
evolution <- data.frame(transaction, date, type, amount, oldbalance, row.names=transaction, stringsAsFactors=FALSE);
evolution$date <- as.Date(evolution$date, "%Y-%m-%d");
evolution <- transform(evolution, newbalance = oldbalance + amount);
evolution
then running xtable gives
xtable(evolution)
Error in Math.Date(x + ifelse(x == 0, 1, 0)) :
abs not defined for Date objects
But it can be useful to use xtable in such a case to do some filtering of dates
evolution$date <- as.Date(evolution$date, "%Y-%m-%d")
startdate <-as.Date("2010-02-01");
enddate <-as.Date("2010-03-30");
newdate <-evolution[which (evolution$date >= startdate & evolution$date <= enddate),]
newdate
> newdate
transaction date type amount oldbalance newbalance
2 2 2010-02-28 debit -1000.97 4500 3499.03
> xtable(newdate)
Error in Math.Date(x + ifelse(x == 0, 1, 0)) :
abs not defined for Date objects
This is arguably a bug in xtable - you may want to report it to the maintainer.
A temporary work-around is to call as.character() on the classes that xtable misinterprets (apart from "Date" I can think of "POSIXt" but there may be others), e.g.:
xtable <- function(x, ...) {
for (i in which(sapply(x, function(y) !all(is.na(match(c("POSIXt","Date"),class(y))))))) x[[i]] <- as.character(x[[i]])
xtable::xtable(x, ...)
}
It does appear that xtable does not always play nicely with columns of class Date. (It does have zoo and ts methods, but those may not help if you have a single column of dates/times in a data frame, as coercion to zoo appears to alter the column names in the resulting table.) A few notes:
The error is actually being thrown by print.xtable, (not xtable.data.frame), which is called by default in order to display the results of xtable in the console. So you'd find that if you stored the results of xtable in a variable, you'd get no error, but then when you tried to print it, the same error would pop up.
Since you've wisely stored your dates in YYYY-MM-DD format, converting them to Date objects actually isn't necessary to use ordered selections, since they will sort properly as characters. So you could actually get away with simply keeping them as characters.
In cases with more complex date/time objects you could do the subsetting first and then convert those columns to characters. Or create a wrapper for xtable.data.frame and add the lines at the beginning,
dates <- sapply(x,FUN = function(x){class(x) == "Date"})
x[,dates] <- as.character(x[,dates])
checking for class Date, or whatever class you're dealing with.
IMHO, xtable.data.frame should probably be checking for Dates, and possibly for other POSIX classes as well and converting them to strings as well. This may be a simple change, and may be worth contacting the package author about.
Lastly, the semicolons as line terminators are not necessary. :) Habit from another language?
As the maintainer of xtable I would like to state what I see as the true position regarding dates in xtable.
This is not really a bug, but the absence of a feature you might think is desirable.
The problem is that xtable only can deal with three different classes of columns: logical; character; and numeric. If you try to submit a table where the class of a column is Date, then it cannot deal with it. The relevant code is the set of xtable methods, the most important of which are xtable.data.frame and xtable.matrix.
The first part of the code for those methods deals with checking the class of the columns being submitted so they can be treated appropriately.
It would be possible to add code to allow columns of class Date as well, but I am not willing to do that.
Firstly, there is an easy work around (at least for straight R code, I can't say for Shiny applications), which is to change any Date column to be a character column:
Second, to allow columns of class Date, would require the addition of an argument to xtable and xtable methods (of which there are currently 31) as well as to xtableFtable and xtableList. That is fraught with problems because of the large number of reverse dependencies for xtable. (Haven't counted, but if you look at xtable on CRAN you will see a stack of depends, imports and suggests.) I am going to break some packages, maybe a lot of packages if I make that sort of change. Backward compatibility is a serious problem with xtable.
Why is an extra argument necessary? Because the end result of using xtable, or more to the point print.xtable, is a string of characters. How the columns of the data frame, matrix or other structure submitted to xtable are treated is determined by firstly how they are classified (logical, character, or numeric), then by the arguments align, digits and display which can all be vectors to allow for different treatment of different columns. So if dates were to be allowed, you would need an extra argument to specify how they would be formatted, because at some point they need to be converted to character to produce the final table output.
Same answer as above, but replace sapply with vapply, slightly safer. Creates a new function xtable2 so you can compare the output. Don't quite understand #David Scott's reluctance to put this idea in xtable.
library(xtable)
xtable2 <- function(x, ...) {
# get the names of variables that are dates by inheritance
datevars <- colnames(x)[vapply(x, function(y) {
inherits(y, c("Date", "POSIXt", "POSIXct"))
}, logical(1))]
for (i in datevars){
x[ , i] <- as.character(x[, i])
}
xtable::xtable(x, ...)
}
example
> str(dat)
'data.frame': 200 obs. of 9 variables:
$ x5 : num 0.686 0.227 -1.762 0.963 -0.863 ...
$ x4 : num 1 3 3 4 4 4 4 5 6 1 ...
$ x3 : Ord.factor w/ 3 levels "med"<"lo"<"hi": 3 2 2 2 3 3 2 1 3 3 ...
$ x2 : chr "d" "c" "b" "d" ...
$ x1 : Factor w/ 5 levels "bobby","cindy",..: 3 2 4 2 3 5 2 2 5 5 ...
$ x7 : Ord.factor w/ 5 levels "a"<"b"<"c"<"d"<..: 4 2 2 2 4 5 4 5 5 4 ...
$ x6 : int 5 4 2 3 4 1 4 3 4 2 ...
$ date1: Date, format: "2020-03-04" "1999-01-01" ...
$ date2: POSIXct, format: "2020-03-04" "2005-04-04" ...
> xtable2(dat)
% latex table generated in R 4.0.3 by xtable 1.8-4 package
% Wed Dec 9 08:59:07 2020
\begin{table}[ht]
\centering
\begin{tabular}{rrrllllrll}
\hline
& x5 & x4 & x3 & x2 & x1 & x7 & x6 & date1 & date2 \\
\hline
1 & 0.69 & 1.00 & hi & d & greg & d & 5 & 2020-03-04 & 2020-03-04 \\
2 & 0.23 & 3.00 & lo & c & cindy & b & 4 & 1999-01-01 & 2005-04-04 \\
3 & -1.76 & 3.00 & lo & b & marcia & b & 2 & 2020-03-04 & 2020-03-04 \\
4 & 0.96 & 4.00 & lo & d & cindy & b & 3 & 2020-03-04 & 2020-03-04 \\
5 & -0.86 & 4.00 & hi & d & greg & d & 4 & 2005-04-04 & 2005-04-04 \\
6 & -0.30 & 4.00 & hi & b & peter & f & 1 & 2005-04-04 & 2020-03-04 \\
7 & -1.39 & 4.00 & lo & c & cindy & d & 4 & 1999-01-01 & 2005-04-04 \\
8 & -1.71 & 5.00 & med & f & cindy & f & 3 & 2005-04-04 & 2020-03-04 \\
[snip]
\hline
\end{tabular}
\end{table}
I am using a script to scrape the required content from a link in which there are different subjects.
library(rvest)
url <- "https://ssb.bannerprod.memphis.edu/prod/bwckschd.p_get_crse_unsec"
query <- list(term_in = "202110", sel_subj = "dummy", sel_day = "dummy",
sel_schd = "dummy", sel_insm = "dummy", sel_camp = "dummy",
sel_levl = "dummy", sel_sess = "dummy", sel_instr = "dummy",
sel_ptrm = "dummy", sel_attr = "dummy", sel_subj = "ARCH",
sel_crse = "", sel_title = "", sel_insm = "%",
sel_from_cred = "", sel_to_cred = "", sel_camp = "%",
sel_levl = "%", sel_ptrm = "%", sel_instr = "%",
sel_attr = "%", begin_hh = "0", begin_mi = "0",
begin_ap = "a", end_hh = "0", end_mi = "0",
end_ap = "a")
In the above query sel_subj changes for every different subjects
html <- read_html(httr::POST(url, body = query))
classes <- html %>% html_nodes(xpath = "//th/a") %>% html_text()
instructor_nodes <- html %>%
html_nodes(xpath = "//td[#class='dddefault']/a[contains(#href, 'mailto')]")
instructors <- html_attr(instructor_nodes, "target")
emails <- html_attr(instructor_nodes, "href")
length(classes)
[1] 32
length(instructors)
[1] 39
length(emails)
[1] 39
sq <- seq(max(length(classes), length(instructors), length(emails)))
data.frame(classes[sq], instructors[sq], emails[sq])
And the result looks like below which is wrong:
classes.sq. instructors.sq. emails.sq.
1 Fundamentals of Design Studio - 23838 - ARCH 1111 - 001 Jennifer L. Thompson mailto:jlthmps5#memphis.edu
2 Fundamentals of Design Studio - 23839 - ARCH 1111 - 002 Pamela J. Hurley mailto:pjhurley#memphis.edu
3 Design Visualization - 11107 - ARCH 1113 - 001 Michael K. Chisamore mailto:mkchsmre#memphis.edu
4 Design Visualization - 18386 - ARCH 1113 - 002 Michael K. Chisamore mailto:mkchsmre#memphis.edu
5 History of Architecture 1 - 23218 - ARCH 1211 - 001 Pamela J. Hurley mailto:pjhurley#memphis.edu
6 Building Technology 2 - 23840 - ARCH 2412 - 001 Marika E. Snider mailto:mesnider#memphis.edu
7 Computer Apps in Design 2 - 11111 - ARCH 2612 - 001 Timothy E. Michael mailto:tmichael#memphis.edu
8 Design Studio 2 - 11112 - ARCH 2712 - 001 Timothy E. Michael mailto:tmichael#memphis.edu
9 Design Studio 2 - 15408 - ARCH 2712 - 002 Andrew M. Parks mailto:amparks#memphis.edu
10 Survey of Interiors+Furniture - 25734 - ARCH 3213 - 001 Andrew M. Parks mailto:amparks#memphis.edu
11 Determinants of Modern Design - 27436 - ARCH 3221 - 001 Michael D. Hagge mailto:mdhagge#memphis.edu
12 Structural Design 2 - 23837 - ARCH 3322 - 001 Michael D. Hagge mailto:mdhagge#memphis.edu
13 Professional Practice - 25097 - ARCH 3431 - 001 Andrew M. Parks mailto:amparks#memphis.edu
14 Design Studio 4 - 11115 - ARCH 3714 - 001 Sonia Raheel mailto:sraheel#memphis.edu
15 Design Studio 4 - 23221 - ARCH 3714 - 002 Pamela J. Hurley mailto:pjhurley#memphis.edu
16 Architecture Independent Study - 11117 - ARCH 4021 - 201 Jennifer L. Barker mailto:jlbrker1#memphis.edu
17 Sustainable Design - 19491 - ARCH 4421 - 001 Jennifer L. Barker mailto:jlbrker1#memphis.edu
18 Internship in Architecture - 21000 - ARCH 4430 - 001 Marika E. Snider mailto:mesnider#memphis.edu
19 Design Studio 6 - 11134 - ARCH 4716 - 001 Pamela J. Hurley mailto:pjhurley#memphis.edu
20 Sustainable Design - 19492 - ARCH 6421 - 001 Marika E. Snider mailto:mesnider#memphis.edu
21 Advanced Design Seminar 2 - 18387 - ARCH 7012 - 001 Marika E. Snider mailto:mesnider#memphis.edu
22 Contemporary Architecture 2 - 24104 - ARCH 7222 - 001 Pamela J. Hurley mailto:pjhurley#memphis.edu
23 Internship in Architecture - 19495 - ARCH 7430 - 001 Jennifer L. Barker mailto:jlbrker1#memphis.edu
24 Adv Professional Practice - 19496 - ARCH 7431 - 001 Jennifer L. Thompson mailto:jlthmps5#memphis.edu
25 Advanced Design Studio 2 - 18389 - ARCH 7712 - 001 Michael D. Hagge mailto:mdhagge#memphis.edu
26 Architecture Research - 25098 - ARCH 7930 - 001 Brian D. Andrews mailto:bdndrews#memphis.edu
27 Architecture Thesis Studio - 19499 - ARCH 7996 - 003 Jennifer L. Thompson mailto:jlthmps5#memphis.edu
28 Architecture Thesis Studio - 19500 - ARCH 7996 - 004 Brian D. Andrews mailto:bdndrews#memphis.edu
29 Architecture Thesis Studio - 19501 - ARCH 7996 - 005 Andrew M. Parks mailto:amparks#memphis.edu
30 Architecture Thesis Studio - 19502 - ARCH 7996 - 006 Michael D. Hagge mailto:mdhagge#memphis.edu
31 Architecture Thesis Studio - 19503 - ARCH 7996 - 007 Brian D. Andrews mailto:bdndrews#memphis.edu
32 Architecture Thesis Studio - 20972 - ARCH 7996 - 008 Michael K. Chisamore mailto:mkchsmre#memphis.edu
33 <NA> Pamela J. Hurley mailto:pjhurley#memphis.edu
34 <NA> Jennifer L. Barker mailto:jlbrker1#memphis.edu
35 <NA> Michael K. Chisamore mailto:mkchsmre#memphis.edu
36 <NA> Pamela J. Hurley mailto:pjhurley#memphis.edu
37 <NA> Jennifer L. Thompson mailto:jlthmps5#memphis.edu
38 <NA> Brian D. Andrews mailto:bdndrews#memphis.edu
39 <NA> Marika E. Snider mailto:mesnider#memphis.edu
But in the link, the data looks different.
For example:
There are few classes without any instructor and email (It is mentioned TBA) like below:
And there are few other classes that have two/three/four/multiple instructors.
And there are few other classes with the same instructor given multiple times like below:
For such data I want my output to be looked like below:
classes.sq. instructors.sq. emails.sq.
1 Fundamentals of Design Studio - 23838 - ARCH 1111 - 001 Jennifer L. Thompson mailto:jlthmps5#memphis.edu
2 Fundamentals of Design Studio - 23839 - ARCH 1111 - 002 TBA
3 Design Visualization - 11107 - ARCH 1113 - 001 Michael K. Chisamore,Pamela J. Hurley mailto:mkchsmre#memphis.edu,pjhurley#memphis.edu
4 Design Visualization - 18386 - ARCH 1113 - 002 Pamela J. Hurley,Michael K. Chisamore mailto:pjhurley#memphis.edu,mkchsmre#memphis.edu
5 History of Architecture 1 - 23218 - ARCH 1211 - 001 Marika E. Snider mailto:mesnider#memphis.edu
6 Building Technology 2 - 23840 - ARCH 2412 - 001 Timothy E. Michael mailto:tmichael#memphis.edu
P.S. if the posted URL link doesn't work. Please follow this:
In this link `https://ssb.bannerprod.memphis.edu/prod/bwckschd.p_disp_dyn_sched`
Select by term -> Spring Term 2021 (view only) -> Submit
Subject -> select ARCH Architecture -> scroll down and click Class Search
How to deal with missing data (TBA), multiple instructors, and the same instructor given multiple times?
The problem is with using the html_nodes() function. This function will return a list of values without any regard to which node the value was found. Since you webpage will have sometime have multiple instructors per class or none, a more targeted approach is needed.
In this code block we first find each of the class nodes which contain all of the information we want. Then we parse each of those node individually (inside the lapply function) to extract the instructors and email also checking for empty fields. There is a single line in each data frame for each instructor, so some data frame will have multiple lines if there are multiple instructors.
We assemble a list of data frames (bind_rows) for each class and then merge the instructor and email results for the same class
library(rvest)
library(dplyr)
url <- "https://ssb.bannerprod.memphis.edu/prod/bwckschd.p_get_crse_unsec"
query <- list(term_in = "202110", sel_subj = "dummy", sel_day = "dummy",
sel_schd = "dummy", sel_insm = "dummy", sel_camp = "dummy",
sel_levl = "dummy", sel_sess = "dummy", sel_instr = "dummy",
sel_ptrm = "dummy", sel_attr = "dummy", sel_subj = "ARCH",
sel_crse = "", sel_title = "", sel_insm = "%",
sel_from_cred = "", sel_to_cred = "", sel_camp = "%",
sel_levl = "%", sel_ptrm = "%", sel_instr = "%",
sel_attr = "%", begin_hh = "0", begin_mi = "0",
begin_ap = "a", end_hh = "0", end_mi = "0",
end_ap = "a")
html <- read_html(httr::POST(url, body = query))
classes <- html %>% html_nodes("th.ddtitle") %>% html_text()
classinfo <- html %>% html_nodes("tr td.dddefault")
classinfo <- html %>% html_nodes(xpath = ".//tr/td[#class='dddefault']")
classinfo <- classinfo[nchar( html_text(classinfo))>50 ] #eliminate the extra found nodes
classlink <- classinfo %>% html_nodes("a") %>% html_attr("href") #find all links
classlinktext <- classinfo %>% html_nodes("a") %>% html_text() #find the link text
classlink <- classlink[classlinktext=="View Catalog Entry"] #keep only the links for "View Catalog Entry"
dfs <-lapply(1:length(classinfo), function(i) {
# classname <-classes[i] %>% html_node(xpath = ".//a") %>% html_text()
instructor_node <- classinfo[i] %>% html_nodes("table.datadisplaytable") %>%
html_nodes(xpath = ".//a[contains(#href, 'mailto')]")
instructors <- html_attr(instructor_node, "target")
emails <- html_attr(instructor_node, "href")
#check to see if instructor was assign if not TBD
if(length(instructors)==0){
instructors <- "TBD"
emails <- "NA"
}
data.frame(classname=classes[i], link=classlink[i], instructors, emails)
})
#merge list into data frame
answer<- bind_rows(dfs)
#consolidation the instructions in the same class
finalanswer<-answer %>% group_by(classes) %>% summarize(instructors2 = paste(instructors, collapse = ", "), emails = paste(emails, collapse = ", "))
# the paste(instructors, collapse = ", ") could be contained within the lapply
# loop but adding it here add some flexibility depending on whether
# answer or final answer is the end result.
head(finalanswer, 16)
tail(finalanswer, 16)
I want to replace every instance of a particular character in a string by another, 's' & '#' in this case
So, San Jose becomes #an Jo#e
I am using the following queries:
UPDATE city SET NewName = REPLACE(Name,'s','#') WHERE(ID<5000);
UPDATE city SET NewName = REPLACE(Name,'S','#') WHERE(ID<5000);
SELECT * FROM city WHERE Name LIKE "%s%" OR "%S%";
This is what the table looks like:
ID Name CountryCode District Population NewName
4 Mazar-e-Sharif AFG Balkh 127800 Mazar-e-#harif
5 Amsterdam NLD Noord-Holland 731200 Amsterdam
15 Enschede NLD Overijssel 149544 Enschede
19 Zaanstad NLD Noord-Holland 135621 Zaanstad
20 ´s-Hertogenbosch NLD Noord-Brabant 129170 ´s-Hertogenbosch
21 Amersfoort NLD Utrecht 126270 Amersfoort
22 Maastricht NLD Limburg 122087 Maastricht
33 Willemstad ANT Curaçao 2345 Willemstad
I am using this database. I have also added a new column to the table, NewName
Do this in one step:
UPDATE city
SET NewName = REPLACE(REPLACE(Name, 's', '#'), 'S', '#')
WHERE(ID < 5000);
Actually, the first will do if the collation for the column is case-insensitive.
Try to use next approach:
UPDATE city SET NewName = REGEXP_REPLACE(Name, '/[s]/ig', '#') WHERE(ID<5000);
OR update your request
UPDATE city SET NewName = REPLACE(REPLACE(Name,'s','#'),'S','#') WHERE(ID<5000);
I have a list (mysql table) of People and their titles as shown in the table below. I also have a list of titles and their categories. How do I assign their categories to the person? The problem arises when there are multiple titles for a person. What is the pythonic way of mapping the title to the category and assigning it to the person?
People Table
Name Title
--------------------
John D CEO, COO, CTO
Mary J COO, MD
Tim C Dev Ops, Director
Title Category table
Title Executive IT Other
-----------------------------
CEO 1
COO 1
CTO 1 1
MD 1
Dev Ops 1
Director 1
Desired output :
Name Title Executive IT Other
---------------------------------------------
John D CEO, COO, CTO 1 1
Mary J COO, MD 1
Tim C Dev Ops, Director 1 1
name_title = (("John D",("CEO","COO","CTO")),
("Mary J",("COO","MD")),
("Tim C",("Dev Ops","Director")))
title_cat = {"CEO": set(["Executive"]),
"COO": set(["Executive"]),
"CTO": set(["Executive"]),
"MD": set(["Executive"]),
"Dev Ops": set(["IT"]),
"Director": set(["Other"])}
name_cat = [(name, reduce(lambda x,y:x|y, [title_cat[title]for title in titles])) for name,titles in name_title]
It would be nice if there was a union which behaved like sum on sets.
people=['john','Mary','Tim']
Title=[['CEO','COO','CTO'],['COO','MD'],['DevOps','Director']]
title_des={'CEO':'Executive','COO':'Executive','CTO':'Executive',
'MD':'Executive','DevOps':'IT','Director':'Others'
}
people_des={}
for i,x in enumerate(people):
people_des[x]={}
for y in Title[i]:
if title_des[y] not in people_des[x]:
people_des[x][title_des[y]]=[y]
else:
people_des[x][title_des[y]].append(y)
print(people_des)
output:
{'Tim': {'IT': ['DevOps'], 'Others': ['Director']}, 'john': {'Executive': ['CEO', 'COO', 'CTO']}, 'Mary': {'Executive': ['COO', 'MD']}}
Start by arranging your input data in a dictionary-of-lists form:
>>> name_to_titles = {
'John D': ['CEO', 'COO', 'CTO'],
'Mary J': ['COO', 'MD'],
'Tim C': ['Dev Ops', 'Director']
}
Then loop over the input dictionary to create the reverse mapping:
>>> title_to_names = {}
>>> for name, titles in name_to_titles.items():
for title in titles:
title_to_names.setdefault(title, []).append(name)
>>> import pprint
>>> pprint.pprint(title_to_names)
{'CEO': ['John D'],
'COO': ['John D', 'Mary J'],
'CTO': ['John D'],
'Dev Ops': ['Tim C'],
'Director': ['Tim C'],
'MD': ['Mary J']}
I propose this if you mean you have the string:
s = '''Name Title
--------------------
John D CEO, COO, CTO
Mary J COO, MD
Tim C Dev Ops, Director
Title Executive IT Other
-----------------------------
CEO 1
COO 1
CTO 1
MD 1
Dev Ops 1
Director 1
'''
lines = s.split('\n')
it = iter(lines)
for line in it:
if line.startswith('Name'):
break
next(it) # '--------------------'
for line in it:
if not line:
break
split = line.split()
titles = split[2:]
name = split[:2]
print ' '.join(name), titles
# John D ['CEO,', 'COO,', 'CTO']
# Mary J ['COO,', 'MD']
# Tim C ['Dev', 'Ops,', 'Director']