1

I am new to java 8 stream api and I am seeking for a solution to run through my list of objects and aggretate certain property to be able in the end to get a new list of that property type and all the aggreation results.

for example my list has 10 person objects inside and i want a list of all the age differences based on first persons age

is that even in java possible with stream?

for example:

person1.age = 10
person2.age = 12
person3.age = 20
person4.age = 25
person5.age = 30

after doing stream magic the results should of type int and be looking like this

0
2 //based on first age 12 - 10
10 // based on first age 20 - 10
15 // ...
20
Stefan Zobel
  • 3,182
  • 7
  • 28
  • 38
Joey
  • 121
  • 1
  • 9
  • 2
    *is that even in java possible without writing tooo much code?* I don't even find what code have you tried so far. – Naman Mar 06 '17 at 12:33
  • i mean is that possible without writing custom colletor for stream and that stuff.. – Joey Mar 06 '17 at 12:34
  • 1
    Let us see, what you've tried and then lets figure out what can be done to improve. – Naman Mar 06 '17 at 12:35

3 Answers3

2

I assume that you have a class called Person with a getAge() getter on it. Then you can do:

list.stream()
    .skip(1)
    .map(Person::getAge)
    .map(age -> age - list.get(0).getAge())
    .map(Math::abs)
    .forEach(System.out::println);

.skip(1) - skips the first person from the list so the result won't contain 0 produced by comparing first person's age to themselves.

.map(Math::abs) - takes the absolute value as "difference" is always positive (whether I have 10 years and you have 20, or I have 20 and you have 10, the difference is 10).

You might want to add .distinct() to remove duplications.

Finally, you might want to use different terminal operation - e.g. .collect(toList()), rather than printing.

Jaroslaw Pawlak
  • 5,538
  • 7
  • 30
  • 57
1

Assuming that the list is already sorted(if not you would need to sort by age). You could extract lst.get(0).getAge() and then do something like this:

List<Integer> diff = lst.stream().map((x)->x.getAge()-firstAge).collect(Collectors.toList());

I am not condoning naming any List lst. That is bad practice, but seeing as you did not share any code with us, I do not know what you named your list of people.

CraigR8806
  • 1,584
  • 13
  • 21
  • *i mean is that possible without writing custom colletor for stream and that stuff* from a comment from the OP – Naman Mar 06 '17 at 12:37
  • @nullpointer actually I would argue that this would not be considered a 'custom collector' as it utilizes `Collectors.toList()` to generate the returned `List` from the `Stream`. – CraigR8806 Mar 06 '17 at 12:40
  • the `{return ...;}` lambda syntax seems a bit unnecessary – Patrick Parker Mar 06 '17 at 12:42
  • is there a way to get the previous and actual item and accumulate them to new list which is output using streams? – Joey Mar 06 '17 at 12:43
  • 1
    @Jo-ing that's a completely different question. and it has been answered. http://stackoverflow.com/questions/20470010/collect-successive-pairs-from-a-stream – Patrick Parker Mar 06 '17 at 12:46
0

I supposed you had a Person class, and I made my code on this supposition because you give anything.

public static void main(String [] args) {
    List<Person> list = new ArrayList<Person>();
    Person person1 = new Person();
    person1.age = 10;
    Person person2 = new Person();
    person2.age = 12;
    Person person3 = new Person();
    person3.age = 20;
    Person person4 = new Person();
    person4.age = 25;
    Person person5 = new Person();
    person5.age = 30;

    list.add(0,person1);
    list.add(person2);
    list.add(person3);
    list.add(person4);
    list.add(person5);

    list.stream().forEach(person -> System.out.println(person.age-list.get(0).age));
}

And here you have

If you want to put the values in a list :

List<Integer> list2 = new ArrayList<Integer>();
list.stream().forEach(person -> list2.add(person.age-list.get(0).age));

Because you write person.age=10 it appears you set the visibility of age as public, which is not very good, you need to set it as private and provide a getter for it :

public int getAge(){
    return this.age;
}
azro
  • 53,056
  • 7
  • 34
  • 70
  • 1
    `list.add(0,person1);` - this `0` is redundant. Your stream should have `.skip(1)`, otherwise it will always print 0 as first result as it compares first person to itself. Finally, it's a bad practice to have so many operations in single lamba - you should use multiple `.map(...)` instead. – Jaroslaw Pawlak Mar 06 '17 at 13:08
  • 1
    Regarding your edit, you shouldn't have a stateful consumer function which adds to some list. That's what `.collect(...)` is for. – Jaroslaw Pawlak Mar 06 '17 at 13:22