Exercise 1
Please implement code and data structures that read the files:
src/test/java/resources/people.csv
src/test/java/resources/relationships.csv
and use them to build an in-memory data structure that represents the people in the file and their relationships with each other.
Exercise 2 - Validate correct people loaded
Write a test to validate that you have loaded the expected number of people.
Exercise 3 - Validate correct relationships loaded
Write a test to validate that the following people have the correct expected number of connections to other people
- Bob (4 relationships)
- Jenny (3 relationships)
- Nigel (2 relationships)
- Alan (0 relationships)
Exercise 4 - Write a method that calculates the size of the extended family
Write a method which, when passed the object representing a particular person, returns an int representing the size of their extended family including themselves. Their extended family includes anyone connected to them by a chain of family relationships of any length, so your solution will need to work for arbitrarily deep extended families. It should not count their friends. Write tests that validate this returns the correct result for the families of:
- Jenny (4 family members)
- Bob (4 family members)
Solution
package com.graph;
import java.util.ArrayList;
import java.util.List;
public class People {
private String name;
private String email;
private int age;
boolean visited = false;
private List<Relatives> relations = new ArrayList<>();
public People(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}
public int getRelationShipCount() {
return this.relations.size();
}
public void addRelationShip(People people, String relationShip) {
if (this.getRelationShipCount() > 0) {
this.getRelations().forEach(rel -> {
// if user already in the relationship list then don't add the user in the
// relations
if (rel.getPerson().getEmail().equals(people.getEmail())) {
return;
}
});
}
Relatives newRelationShip = new Relatives(Relation.valueOf(relationShip), people);
this.relations.add(newRelationShip);
// Relation is bi-directional so add this to the relation of person
newRelationShip = new Relatives(Relation.valueOf(relationShip), this);
people.getRelations().add(newRelationShip);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List<Relatives> getRelations() {
return relations;
}
public void setRelations(List<Relatives> relations) {
this.relations = relations;
}
public boolean isVisited() {
return visited;
}
public void setVisited(boolean visited) {
this.visited = visited;
}
@Override
public String toString() {
return "name: " + this.getName() + " email: " + this.getEmail() + " age: " + this.getAge();
}
}
package com.graph;
public enum Relation {
FAMILY,
FRIEND
}
package com.graph;
public class Relatives {
private Relation relationShip;
private People person;
public Relatives(Relation relationShip, People person) {
super();
this.relationShip = relationShip;
this.person = person;
}
public Relation getRelationShip() {
return relationShip;
}
public void setRelationShip(Relation relationShip) {
this.relationShip = relationShip;
}
public People getPerson() {
return person;
}
public void setPerson(People person) {
this.person = person;
}
}
package com.graph;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
public class ReadPersonAndRelationship {
public List<People> getAllPeople() {
List<People> peopleList = new ArrayList<>();
try (FileReader fr = new FileReader("src/test/resources/people.csv");
BufferedReader br = new BufferedReader(fr);) {
// read line by line
String line;
while ((line = br.readLine()) != null) {
String[] peoples = line.split(",");
People p = new People(peoples[0], peoples[1], Integer.valueOf(peoples[2]));
peopleList.add(p);
}
} catch (IOException e) {
System.err.format("IOException: %s%n", e);
}
return peopleList;
}
public List<Relatives> getAllPeopleRelationShip(List<People> listPeople) {
List<Relatives> relationshipsList = new ArrayList<>();
try (FileReader fr = new FileReader("src/test/resources/relationships.csv");
BufferedReader br = new BufferedReader(fr);) {
// read line by line
String line;
while ((line = br.readLine()) != null) {
if (line.trim().length() == 0) {
continue; // Skip blank lines
}
String[] rr = line.split(",");
People currentPerson = getPersonByEmail(listPeople, rr[0]);
People nextPerson = getPersonByEmail(listPeople, rr[2]);
if (null != nextPerson && null != currentPerson) {
currentPerson.addRelationShip(nextPerson, rr[1]);
}
}
} catch (IOException e) {
System.err.format("IOException: %s%n", e);
}
return relationshipsList;
}
private People getPersonByEmail(List<People> peopleList, String email) {
List<People> listPeople = peopleList.stream().filter(people -> people.getEmail().equals(email))
.collect(Collectors.toList());
if (null != listPeople && !listPeople.isEmpty()) {
return listPeople.get(0);
}
return null;
}
public static void main(String[] args) throws IOException {
ReadPersonAndRelationship r = new ReadPersonAndRelationship();
List<People> allPeople = r.getAllPeople();
System.out.println(allPeople.toString());
allPeople.forEach(people -> {
System.out.println(r.getRelationShipCount(people.getName()));
System.out.println(people.getName() + " : " + r.getExtendedFamilyCount(people.getName()));
});
}
public int getRelationShipCount(String name) {
List<People> peopleList = getAllPeople();
getAllPeopleRelationShip(peopleList);
// should be based on the unique key as email
List<People> peoples = peopleList.stream().filter(people -> people.getName().equalsIgnoreCase(name))
.collect(Collectors.toList());
if (null == peoples || peoples.size() > 1 || peoples.isEmpty()) {
return 0;
}
return peoples.get(0).getRelationShipCount();
}
public int getExtendedFamilyCount(String name) {
List<People> peopleList = getAllPeople();
getAllPeopleRelationShip(peopleList);
Deque<People> stack = new LinkedList<>();
People start = peopleList.stream().filter(people -> people.getName().equalsIgnoreCase(name))
.collect(Collectors.toList()).get(0);
if (null != start) {
stack.push(start);
start.setVisited(true);
}
int extendedFamilyCount = 0;
while (!stack.isEmpty()) {
People poped = stack.pop();
extendedFamilyCount++;
poped.getRelations().forEach(rel -> {
if (!rel.getPerson().isVisited() && rel.getRelationShip().equals(Relation.FAMILY)) {
stack.push(rel.getPerson());
rel.getPerson().setVisited(true);
}
});
}
return extendedFamilyCount;
}
}
Files
People.csv
Bob,[email protected],31
Derek,[email protected],25
Anna,[email protected],25
Jenny,[email protected],52
Pete,[email protected],57
Kerry,[email protected],29
Joe,[email protected],28
Nigel,[email protected],40
Amber,[email protected],12
Finn,[email protected],15
Alan,[email protected],23
Dave,[email protected],49
.....................................
relationships.csv
[email protected],FAMILY,[email protected]
[email protected],FAMILY,[email protected]
[email protected],FAMILY,[email protected]
[email protected],FAMILY,[email protected]
[email protected],FAMILY,[email protected]
[email protected],FAMILY,[email protected]
[email protected],FRIEND,[email protected]
[email protected],FAMILY,[email protected]
[email protected],FAMILY,[email protected]
[email protected],FAMILY,[email protected]
[email protected],FAMILY,[email protected]
[email protected],FRIEND,[email protected]
[email protected],FAMILY,[email protected]
[email protected],FRIEND,[email protected]
[email protected],FRIEND,[email protected]
[email protected],FRIEND,[email protected]
kotlin
andgradle
tags, are these tags really necessary? \$\endgroup\$kotlin("jvm")
and Gradle to build it, but I don't see any traces of either Kotlin or Gradle in the code so I'm removing those tags. This is Java code, not Kotlin. And just because you're using Gradle doesn't mean that your code is about Gradle. \$\endgroup\$