简体   繁体   中英

Iterate over two list with just one Iterator Java

I'm having some problems I have two classes and each one returns a Iterator, there is a class that return the values named Student. With this code I can iterate over one class and I'd like to know if there is a way to iterate over the other class without adding a second while at my Machine class. Here is how my code looks like:

import java.util.*;
import java.lang.reflect.*;

class ClassRoom1{
    ArrayList<Student> al = new ArrayList<Student>();
    Student st; 
    public ClassRoom1(){
        st = new Student("Michael", "Smith", 12);
        al.add(st);
        st = new Student("Jennifer", "Lopez", 13);
        al.add(st);
    }

    public void addStudent(String name, String lastName, int age) {
        Student st = new Student(name, lastName, age);
        al.add(st);
    }

    public ArrayList getStudents(){
        return al;
    }

    public Iterator returnIter(){
        Iterator iter = getStudents().iterator();
        return iter;
    }
}

class ClassRoom2{
    ArrayList<Student> al = new ArrayList<Student>();
    Student st; 
    public ClassRoom2(){
        st = new Student("Brian", "Con", 15);
        al.add(st);
        st = new Student("Megan", "Bell", 15);
        al.add(st);
    }

    public void addStudent(String name, String lastName, int age) {
        Student st = new Student(name, lastName, age);
        al.add(st);
    }

    public ArrayList getStudents(){
        return al;
    }

    public Iterator returnIter(){
        Iterator iter = getStudents().iterator();
        return iter;
    }
}

public class Machine{
    Student st;
    ClassRoom1 clrm1 = new ClassRoom1();
    ClassRoom2 clrm2 = new ClassRoom2();    

    public static void main(String[] args){
        Machine mch = new Machine();
        ArrayList al = new ArrayList();
        Iterator iter = al.iterator();
        mch.printStudens(iter);
    }

    void printStudens(Iterator iter){
        iter = clrm1.returnIter();
        while(iter.hasNext()){
            st = (Student) iter.next();
            System.out.println("\nName: " + st.getName() + "\nLast name: " + st.getLastName() + "\nAge: " + st.getAge());
        }
    }
}

First of all, instead of code duplication, use OO:

class ClassRoom{
    private List<Student> al;
    public ClassRoom1(List<Student> studentList){
        a1 = new ArrayList(studentList);
    }

    public void addStudent(String name, String lastName, int age) {
        al.add(new Student(name, lastName, age));
    }

    public List<Student> getStudents(){
        return al;
    }

    public Iterator<Student> returnIter(){
        return getStudents().iterator();
    }
}

Then clrm1 and clrm2 are objects of ClassRoom. You can actually hold arbitrary many ClassRoom objects in an own list and do nested iterations, firstly over all ClassRooms, within which you iterate over all Students in the current ClassRoom.


Update:

If you once need to combine iterators (no necessity here), I'd either write my own little concatenating iterator which, eg sequencially, iterates over the iterators it holds, or use Guava's Iterator.concat() , which "Combines multiple iterators into a single iterator". Either way, you wouldn't have to duplicate any data.

I wouldn't call a variable with a name that resembles it's type (which might change), but with what it will contain:

ArrayList<Student> students = new ArrayList<Student>();

I would change the addStudent method to accept a Student , rather than a name, lastname and age.

  public void addStudent(Student newStudent) 
  {
          students.add(newStudent);
  }

You can then add a student like:

class1.addStudent(new Student("jennifer", "lopez", 30));

But also add the same student to different classes:

Student jennifer = new Student("jennifer", "lopez", 30);
class1.addStudent(jennifer);
class2.addStudent(jennifer);

Finally, yes, you need two iterators in the loop :)

Your design is totally wrong. You shouldn't create two different (Java) Classes for each (school) ClassRoom. Just create one:

public class ClassRoom
{
    ... all your stuff here

    public void addStudent(Student st)
    {
        students.add(st);
    }

    public List<Student> getStudents()
    {
        return students;
    }
}

Then you can create multiple classes like this and put them in an array:

List<ClassRoom> rooms = new ArrayList<ClassRoom>();

ClassRoom room1 = new ClassRoom("5 Latin Sience");
room1.addStudent(new Student("Anna", "Bell", 12));
room1.addStudent(new Student("Martin", "Foo", 12));
room1.addStudent(new Student("Stef", "Bar", 12));


ClassRoom room2 = new ClassRoom("4 Maths");
room2.addStudent(new Student("Anna", "Bell", 11));
room2.addStudent(new Student("Martin", "Foo", 11));
room2.addStudent(new Student("Stef", "Bar", 15));

// put them int the array.
rooms.add(room1);
rooms.add(room2);

Now, you can iterate over each class room and then iterate over each student with a nested for loop:

for (ClassRoom room : rooms)
{
    for (Student st : room.getStudents())
    {
        System.out.println(... student details here ...);
    }
}

I agree with the answers about bad design, but to answer the actual question get one iterator for both lists the code below should work. It's will be computational expensive because of array copying so you may want to use a Linked List to mitigate that.

clrm1.getStudents().clone().addAll(clrm2.getStudents()).iterator();

Another option is to use a list of Class object with a list of students and then a flattening iterator .

I don't see a reason for different classes for the two classrooms: they're identically.

public class Classroom {
  // each classroom has a list of students
  List<Student> students = new ArrayList<Student>();

  // each classroom has a method to add a new student
  public void addStudent(String name, String lastName, int age) {
    Student st = new Student(name, lastName, age);
    al.add(st);
  }

  // each classroom has a method to "show" his students
  public List<Student> getStudents() {
    return students;
  }
}

Now you have a machine :

public class Machine{

    // a list of classrooms
    List<Classroom> classRooms = new ArrayList<Classroom>();

    // just to start the application
    public static void main(String[] args){
        Machine machine = new Machine();
        machine.printStudents();
    }

    public Machine() {
      // we initialize the classrooms
      // Note - a machine wouldn't create classes, this is just for the demo
      Classroom class1 = new Classroom();
      class1.addStudent("Michael", "Smith", 12);
      class1.addStudent("Jennifer", "Lopez", 13);
      classRooms.add(class1);

      Classroom class2 = new Classroom();
      class2.addStudent("Brian", "Con", 15);
      class2.addStudent("Brian", "Con", 15);          
      classRooms.add(class2);
    }

    void printStudents() {
      for (Classroom class:classrooms) {
        // one could print the classname at this place
        for (Student student: class.getStudents()) {
          System.out.println("\nName: " + st.getName() + "\nLast name: " + st.getLastName() + "\nAge: " + st.getAge());
        }
      }
    }
}

This is quite different from your solution - only one class for classrooms and no iterators (we don't need them). Try it and compare it to your code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM