Home > Software engineering >  Return a list with the second youngest people in age Java
Return a list with the second youngest people in age Java

Time:05-26

The idea is to return the second youngest persons from an array Person type. I have this but don't know if it's the best solution, how do you see that approach? or what would be another good idea to resolve this. Thanks any suggestions

this is the class:

public class Persona {

    private String nombre;
    private Integer edad;

    public String getNombre() {
        return nombre;
    }

    public void setNombre(String nombre) {
        this.nombre = nombre;
    }

    public Integer getEdad() {
        return edad;
    }

    public void setEdad(Integer edad) {
        this.edad = edad;
    }

    public Persona(String nombre, Integer edad) {
        this.nombre = nombre;
        this.edad = edad;
    }
}

and the method to make the return also a list with example values (I just sorted the list and then using a filter quit the people with the first value and then filter with the new first value to save only that values)

public static void main(String[] args) {
        ArrayList<Persona> listaPrueba = new ArrayList<Persona>();
        listaPrueba.add(new Persona("Patricia", 21));
        listaPrueba.add(new Persona("Juan", 22));
        listaPrueba.add(new Persona( "Ana", 45));
        listaPrueba.add(new Persona("John", 22));
        listaPrueba.add(new Persona( "Max", 21));
        listaPrueba.add(new Persona("Peter", 50));

        segundoMayor(listaPrueba).stream().forEach(item -> System.out.println(item.getNombre()   " "  item.getEdad()));
    }

public static List<Persona> segundoMayor(ArrayList<Persona> lista){
        lista.sort(Comparator.comparing(Persona::getEdad));
        List<Persona> listaFiltrada = lista.stream().filter(item -> !item.getEdad().equals(lista.get(0).getEdad())).collect(Collectors.toList());
        return listaFiltrada.stream().filter(item -> item.getEdad().equals(listaFiltrada.get(0).getEdad())).collect(Collectors.toList());
    }

the output should be:

Juan 22 John 22

CodePudding user response:

I prefer to find the list in a single parse of the array like this

public static List<Persona> segundoMayor(List<Persona> lista){
    lista.sort(Comparator.comparing(Persona::getEdad));
    Persona first = lista.get(0), second = null;
    List<Persona> secondRankList = new ArrayList<>();
    for(Persona persona: lista) {
        if(second == null && persona.getEdad() > first.getEdad()) {
            second = persona;
        }
        if(second != null && second.getEdad().equals(persona.getEdad())) {
            secondRankList.add(persona);
        }
    }
    return secondRankList;
}

CodePudding user response:

I don't have my Java IDE setup at the moment, so consider this to be pseudo code (and write your own unit tests to check for bugs). But my solution would be to iterate the list of Persona objects to find the second-youngest age, then iterate the list again to find all objects with that age. Then you can add matching Persona objects to a collection, and/or print them out to the console.

int youngestAge = 1000, secondYoungestAge = 1000;
for (Persona p : listaPrueba) {
    int edad = p.getEdad();
    if (edad < youngestAge) {
        secondYoungestAge = youngestAge;
        youngestAge = edad;
    } else if (edad < secondYoungestAge) {
        secondYoungestAge = edad;
    }
}

if (secondYoungestAge == 1000) {
    throw new NoSuchElementException("No matching Persona!");
}

List<Persona> secondYoungestPersona = new ArrayList<>();
for (Persona p : listaPrueba) {
    int edad = p.getEdad();
    if (edad == secondYoungestAge) {
        secondYoungestPersona.add(p);
        // AND/OR write the name and age to console
        System.out.print(p.getNombre()   " "   edad   " ");
    }
}

This ought to be more efficient than using a TreeMap (sorted by age) or sorting the entire ArrayList (because you don't care about the order of the rest of the items, you just care about the second-youngest items). But if you need to be sure, then carefully write a JMH benchmark to test the three approaches.

CodePudding user response:

Ignoring questions of efficiency, here's a way with streams (you need a good Persona.toString btw)

    Comparator<Persona> compAge = Comparator.comparingInt(Persona::getEdad);

    TreeSet<Persona> tsP = listaPrueba.stream().sorted(compAge)
            .collect(Collectors.toCollection(() -> new TreeSet<>(compAge)));

    System.out.printf("Second youngest is %s%n", tsP.higher(tsP.first()));

CodePudding user response:

Very intresting.
I wrote a solution with streams. Perhaps, it doesn't have the best performance but it has a high readability.

public static List<Persona> segundoMayor(final ArrayList<Persona> lista) {

    // first, sort it by age
    final var sorted = lista
            .stream()
            .sorted(Comparator.comparing(Persona::getEdad))
            .toList();

    // now, find the second youngest age
    final int secondYoungestAge = sorted
            .stream()
            .map(Persona::getEdad)
            .distinct()
            .skip(1)
            .findFirst()
            .orElse(0);

    // at the end: only take the youngest 
    // and second youngest with takeWhile (so we can reduce the iterations)
    // and filter them for the second youngest age
    return sorted
            .stream()
            .takeWhile(persona -> persona.getEdad() <= secondYoungestAge)
            .filter(persona -> persona.getEdad() == secondYoungestAge)
            .toList();
}

  • Related