1

I have a List<String> tennisLines that contains several lines about tennis matches, each line contains information about one tennis match with the name of the tournament, location, round, winner, loser, date etc. separated by a semicolon.

Each tournament has a unique name and contains several tennis matches. I created a TennisTournament class which include the name of the tournament, the location, and the associated tennis matchs List<TennisMatch>etc. The class TennisMatch contains the winner, the loser and the round.

I'm trying to convert the list tennisLines into a List<TennisTournament> tennisTournamentList so basically turn each line into a TennisMatchs instance and add each group of tennis matches into the tennis match list to finally create a TennisTournament object.
I've created a stream Stream<String> streamLines and I can't figure out how to map them into an object that contains another object.

That's an extract of the list, that should be eventually one TennisTournament object, that also contains a list of size 27 List<TennisMatch>

location;tournament;match_date;series;court;surface;round;best_of;winner;loser;wrank;lrank;wpts;lpts;w1;l1;w2;l2;w3;l3;w4;l4;w5;l5;tourney_id
Lyon;Lyon Open;2019-05-19;ATP250;Outdoor;Clay;1st Round;3;Millman J.;Andujar P.;55;93;875;608;6;1;6;3;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-19;ATP250;Outdoor;Clay;1st Round;3;Tsonga J.W.;Lajovic D.;85;33;633;1316;7;6;6;4;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-20;ATP250;Outdoor;Clay;1st Round;3;Humbert U.;Norrie C.;61;41;823;1055;6;1;6;3;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-20;ATP250;Outdoor;Clay;1st Round;3;Johnson S.;Harris L.;59;89;850;617;6;2;7;6;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-20;ATP250;Outdoor;Clay;1st Round;3;Herbert P.H.;Chardy J.;42;40;1053;1065;6;2;7;5;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-20;ATP250;Outdoor;Clay;1st Round;3;Lamasine T.;Sinner J.;270;229;153;215;6;0;7;6;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-20;ATP250;Outdoor;Clay;1st Round;3;Diez S.;Tomic B.;262;82;165;665;6;4;4;1;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-20;ATP250;Outdoor;Clay;1st Round;3;Fritz T.;Vesely J.;46;105;1010;543;7;5;7;6;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-20;ATP250;Outdoor;Clay;1st Round;3;Gasquet R.;Janvier M.;39;199;1105;263;6;7;6;2;7;6;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-21;ATP250;Outdoor;Clay;1st Round;3;Moutet C.;Opelka R.;117;58;495;853;6;3;2;6;7;6;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-21;ATP250;Outdoor;Clay;1st Round;3;Cuevas P.;Hurkacz H.;50;43;963;1040;6;4;6;4;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-21;ATP250;Outdoor;Clay;1st Round;3;Paire B.;Mcdonald M.;51;65;938;796;3;6;7;6;6;1;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-21;ATP250;Outdoor;Clay;2nd Round;3;Johnson S.;Herbert P.H.;59;42;850;1053;7;6;5;7;6;1;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-21;ATP250;Outdoor;Clay;2nd Round;3;Auger-Aliassime F.;Millman J.;28;55;1344;875;7;6;7;5;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-22;ATP250;Outdoor;Clay;2nd Round;3;Paire B.;Cuevas P.;51;50;938;963;6;4;6;3;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-22;ATP250;Outdoor;Clay;2nd Round;3;Shapovalov D.;Humbert U.;23;61;1425;823;2;6;7;6;6;2;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-22;ATP250;Outdoor;Clay;2nd Round;3;Fritz T.;Gasquet R.;46;39;1010;1105;0;0;0;0;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-22;ATP250;Outdoor;Clay;2nd Round;3;Bautista Agut R.;Moutet C.;21;117;1690;495;4;6;6;4;6;3;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-22;ATP250;Outdoor;Clay;2nd Round;3;Tsonga J.W.;Diez S.;85;262;633;165;3;6;7;6;6;3;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-22;ATP250;Outdoor;Clay;2nd Round;3;Basilashvili N.;Lamasine T.;18;270;1925;153;7;5;7;5;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-23;ATP250;Outdoor;Clay;Quarterfinals;3;Fritz T.;Bautista Agut R.;46;21;1010;1690;6;7;6;3;6;4;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-23;ATP250;Outdoor;Clay;Quarterfinals;3;Paire B.;Shapovalov D.;51;23;938;1425;6;3;4;6;7;6;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-23;ATP250;Outdoor;Clay;Quarterfinals;3;Basilashvili N.;Tsonga J.W.;18;85;1925;633;6;4;6;4;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-23;ATP250;Outdoor;Clay;Quarterfinals;3;Auger-Aliassime F.;Johnson S.;28;59;1344;850;6;4;2;6;6;4;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-24;ATP250;Outdoor;Clay;Semifinals;3;Paire B.;Fritz T.;51;46;938;1010;6;4;6;2;0;0;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-24;ATP250;Outdoor;Clay;Semifinals;3;Auger-Aliassime F.;Basilashvili N.;28;18;1344;1925;2;6;7;6;6;4;0;0;0;0;2019-031
Lyon;Lyon Open;2019-05-25;ATP250;Outdoor;Clay;The Final;3;Paire B.;Auger-Aliassime F.;51;28;938;1344;6;4;6;3;0;0;0;0;0;0;2019-031

Here's the TennisTournament classs

public class TennisTournament {
   private String location; 
   private String name;
   private String type;   
   private boolean outside = true;
   private String surface;       
   private LocalDate lastMatchDate;      
   private List<TennisMatch> matches = new ArrayList<>();
   // constructors, getters, setters, etc.

what I've succeeded into making a list of TennisTournament but without the matches inside them using a stream :

tennisLines.stream()
   .skip(1)
   .map(l -> { return l.split(SEPARATOR); }) 
   .forEach(c -> {
          if (c[ROUND_INDEX].equals(THE_FINAL)){
              TennisTournament tournament = 
                         new TennisTournament(c[LOCATION_INDEX], 
                         c[TOURNAMENT_INDEX], c[SERIES_INDEX],   
                         c[COURT_INDEX].equals(OUTDOOR), 
                         c[SURFACE_INDEX],   
                         LocalDate.parse(c[MATCH_DATE_INDEX]));
          }
          tennisTournamentList.add(tournament)
    });
William
  • 58
  • 8

1 Answers1

1

Assuming that an array contains all the lines this should work. You will probably need to adjust some things for your actual application.

After some consideration I modified this to use a loop rather than streams since two independent data structures need to be created. They can both be created in a single loop at the same time. I believe it is more efficient and certainly more compact that my original answer.

Index constants to reference specific array elements. They also aid in documentation.

static int WINNER = 8;
static int LOCATION = 0;
static int TOURNAMENT = 1;
static int DATE = 2;
static int COURT = 4;
static int SURFACE = 5;
static int LOSER = 9;
static int ROUND = 6;
  • Allocate a map to store the TennisMatch instances. The key is the winner of the match
  • Allocate a list to hold the data for the tournament winners.
Map<String, List<TennisMatch>> matches = new HashMap<>();
List<TennisTournament> tournamentWinners = new ArrayList<>();
  • Loop over the lines, skipping the first (column header)
  • split the lines on the ; delimiter
  • create a TennisTournament instance for a the winner by keying on the final round
  • for all the entries, create a map of winner (key) to list of won matches (value).
    • this uses the computeIfAbsent method to create and return a list if one isn't present.
    • other wise, the existing list is used to populate the won matches.
for (int i = 1; i < lines.length; i++) {
    String[] arr = lines[i].split(";");
    if (arr[ROUND].equals("The Final")) {
        tournamentWinners.add(new TennisTournament(arr[LOCATION],
                arr[TOURNAMENT], arr[COURT], arr[SURFACE],
                arr[WINNER], arr[DATE]));
    }
    
    matches.computeIfAbsent(arr[WINNER],
            v -> new ArrayList<>())
            .add(new TennisMatch(arr[WINNER], arr[LOSER],
                    arr[ROUND]));
}   

Now it is a simple matter to add the matches to for the individual who won the tournament by simply getting the tournament winner from the TennisTournament instance and using that as a key into the map of matches.

for (TennisTournament tourney : tournamentWinners) {
    tourney.setMatches(matches.get(tourney.getWinner()));
}

Display the results (in this case only one)

tournamentWinners.forEach(tourney -> {
    System.out.println(tourney);
    for (TennisMatch m : tourney.getMatches()) {
        System.out.println("          " + m);
    }
});

prints

[Lyon, Lyon Open, Outdoor, Clay, 2019-05-25]
          [Paire B., Mcdonald M., 1st Round]
          [Paire B., Cuevas P., 2nd Round]
          [Paire B., Shapovalov D., Quarterfinals]
          [Paire B., Fritz T., Semifinals]
          [Paire B., Auger-Aliassime F., The Final]

Here are the classes. To keep down the "clutter" only essential getters and setters for this example are shown.

class TennisMatch {
    String winner;
    String loser;
    String round;
    
    public TennisMatch(String winner, String loser, String round) {
        this.winner = winner;
        this.loser = loser;
        this.round = round;
    }
    
    @Override
    public String toString() {
        return String.format("[%s, %s, %s]", winner, loser, round);
    }
}

class TennisTournament {
    String location;
    String series;
    String court;
    String surface;
    LocalDate date;
    String winner;
    List<TennisMatch> matches;
    
    public TennisTournament(String location, String series,
            String court, String surface, String winner,
            String stringDate) {
        this.location = location;
        this.series = series;
        this.court = court;
        this.surface = surface;
        this.winner = winner;
        this.date = LocalDate.parse(stringDate);
    }
    
    public List<TennisMatch> getMatches() {
        return matches;
    }
    
    public String getWinner() {
        return winner;
    }
    
    public void setMatches(List<TennisMatch> matches) {
        // defensive copy
        this.matches = new ArrayList<>(matches);
    }
    
    @Override
    public String toString() {
        return String.format("[%s, %s, %s, %s, %s]", location, series,
                court, surface, date);
    }
}
WJS
  • 36,363
  • 4
  • 24
  • 39