I have a class named Person with the following structure:
public class Person {
public final int num;
public final String name;
public final String gender;
public final int age;
public Person (int aNum, String aName, String aGender, int anAge){
this.num = aNum;
this.name = aName;
this.gender = aGender;
this.age = anAge;
}
public static Person lineValues(String line) {
String array = line.split(",");
int numA = array[0];
String nameA = array[1];
String genderA array[2];
int ageA = array[3];
return new Person(numA, nameA, genderA, ageA);
}
}
The data for a single Person comes from a line in the csv file named people.csv:
| Num | Name | Gender |Age |
| --- | ---- | ------ | --- |
| 1 | Fred | Male | 41 |
| 2 | Wilma | Female | 36 |
| 3 | Barney | Male | 38 |
| 4 | Betty | Female | 35 |
Here is my actual question. I have an interface called People which has a function called getGenderCount. This function should go through a Person object and retrieve a map of the count of each gender.
static Function<Stream<Person>,Map<String,Long>> getGenderCount = null;
My issue is that I am having trouble understanding the proper syntax of how to stream an entire class object. I have worked with primitive streams beforehand. Performing a split such as .map(x -> x.split(","))
would not work since that would be of the type String and not Person.
My proposed solution would look like this:
e -> e.map(x -> x.split(","))
.skip(1) // skips the title line
.filter(x -> x.length == 4)
.collect(Collectors.groupingBy(x -> x[2], Collectors.counting()));
But it should be mapping a Person object's information.I do not want to change anything I have so far except for the stream operations and syntax. I want to understand how to pull the variables from Person and find them in a Stream.
CodePudding user response:
Would this do what you want?
Files.lines(Paths.get("people.csv"))
.skip(1)
.map(Person::lineValues) // this method must handle "|" divider chars
.collect(Collectors.groupingBy(Person::getGender, Collectors.counting()));
CodePudding user response:
You need to operate on the stream with the usual methods like map
, filter
or foreach
and can then use the standard access operation.
Stream<Person> people;
people = ...; // initialize stream with some data
// iterate over stream and access each element
people.forEach(person -> { System.out.println(person.name); });
The function getGenderCount
gets a stream of Person as input and returns a map with the genders and their frequency.
Additionally, in Java a string can not be directly assigned to an int. It needs to be converted.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Person {
public final int num;
public final String name;
public final String gender;
public final int age;
public Person(int aNum, String aName, String aGender, int anAge) {
this.num = aNum;
this.name = aName;
this.gender = aGender;
this.age = anAge;
}
public static Person lineValues(String line) {
String array[] = line.split(",");
int numA = Integer.parseInt(array[0]);
String nameA = array[1];
String genderA = array[2];
int ageA = Integer.parseInt(array[3]);
return new Person(numA, nameA, genderA, ageA);
}
static Function<Stream<Person>, Map<String, Long>> getGenderCount = people -> {
return people.collect(Collectors.groupingBy((person -> person.gender), Collectors.counting()));
};
public static void main(String args[]) {
try {
Stream<Person> people = Files.lines(Paths.get("people.csv"))
.map(line -> { System.out.println(line); return line;}) // just to show input
.skip(1) // remove first line
.map(line -> line.substring(line.indexOf("|") 1)) // remove first '|' and in front
.map(line -> line.substring(0, line.lastIndexOf("|"))) // remove last '|' and behind
.map(line -> line.replace(" ", "")) // remove spaces, can cause trouble with spaces within names
.map(line -> line.replace("|", ",")) // change pipe symbols into commas
.map(line -> Person.lineValues(line)); // transform lines into persons
Map<String, Long> genderCount = Person.getGenderCount.apply(people);
System.out.println(genderCount);
} catch (IOException e) {
e.printStackTrace();
}
}
}
produces
$ javac Person.java
$ java Person
| Num | Name | Gender | Age|
| 1 | Fred | Male | 41 |
| 2 | Wilma | Female | 36 |
| 3 | Barney | Male | 38 |
| 4 | Betty | Female | 35 |
{Male=2, Female=2}
$