Home > front end >  If I have a Stream<Class>, how can I access the classes' inherent information such as var
If I have a Stream<Class>, how can I access the classes' inherent information such as var

Time:04-29

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}
$ 
  • Related