Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a new list with values from fields from existing list

Let's say there is a class:

class Person
{
   String name;
   int age;
   City location;
}

Is there some library that will let me create a list of Strings containing each name from the list of persons in one line instead of creating a new list and looping through the other list?

Something like:

List<Person> people = getAllOfThePeople();
List<String> names = CoolLibrary.createList("name", people);

Rather than:

List<Person> people = getAllOfThePeople();
List<String> names = new LinkedList<String>();
for(Person person : people)
{
    names.add(person.getName());
}
like image 286
Nick Vikeras Avatar asked Dec 03 '13 21:12

Nick Vikeras


People also ask

How do you create an ArrayList from an existing list?

Using a Copy Constructor: Using the ArrayList constructor in Java, a new list can be initialized with the elements from another collection. Syntax: ArrayList cloned = new ArrayList(collection c); where c is the collection containing elements to be added to this list.

How do I create a new list of strings?

Create list of strings. To create a list of strings, first use square brackets [ and ] to create a list. Then place the list items inside the brackets separated by commas. Remember that strings must be surrounded by quotes.


2 Answers

You can using Java 8 with lambda expressions :

List<String> listNames = people.stream().map(u -> u.getName()).collect(Collectors.toList());

import java.util.*;
import java.util.function.*;
import java.util.stream.*;

public class Test {
  public static void main(String args[]){
    List<Person> people = Arrays.asList(new Person("Bob",25,"Geneva"),new Person("Alice",27,"Paris"));
    List<String> listNames = people.stream().map(u -> u.getName()).collect(Collectors.toList());
    System.out.println(listNames);
  }
}
class Person
{
   private String name;
   private int age;
   private String location;

  public Person(String name, int age, String location){
    this.name = name;
    this.age = age;
    this.location = location;
  }

  public String getName(){
    return this.name;
  }

}

Output :

[Bob, Alice]

Demo here.


Alternatively, you can define a method that will take your list as parameter and the function you want to apply for each element of this list :
public static <X, Y> List<Y> processElements(Iterable<X> source, Function <X, Y> mapper) {
    List<Y> l = new ArrayList<>();
    for (X p : source) 
        l.add(mapper.apply(p));
    return l;
}

Then just do :

List<String> lNames = processElements(people, p -> p.getName()); //for the names
List<Integer> lAges = processElements(people, p -> p.getAge()); //for the ages
//etc.

If you want to group people by age, the Collectors class provide nice utilities (example):

Map<Integer, List<Person>> byAge = people.stream()
                                         .collect(Collectors.groupingBy(Person::getAge));
like image 161
Alexis C. Avatar answered Sep 19 '22 15:09

Alexis C.


You can do a little trick using Guava library (which I consider the ultimate Java library that you should be using anyway):

class Person
{
   String name;
   int age;
   City location;

  public static final Function<Person, String> getName = new Function<Person, String>() {
    public String apply(Person person) {
      return person.name;
    }
  }
}


List<Person> people = getAllOfThePeople();
List<String> names = FluentIterable.from(people).transform(Person.getName).toList();

The trick is defining the getName public static Function in the Person class.

like image 22
siledh Avatar answered Sep 19 '22 15:09

siledh