浏览类Arraylist对象,无需嵌套循环。

huangapple go评论76阅读模式
英文:

Looking through class Arraylist objects without nested loops

问题

这是我的精简代码。我只会在管理器类中包含一个嵌套循环的示例方法:

import java.util.Scanner;

public class Manager {

    // ...(之前的部分)

    // 通过学号查找学生
    public void findStudent() {
        System.out.println("请输入学生学号:");
        String studentNum = scan.nextLine();

        for (Block block : dorm.getBlockList()) {
            for (Room room : block.getRooms()) {
                for (Student student : room.getRoomStudents()) {
                    if (student.getStudentNumber().equals(studentNum)) {
                        tempStudent = student;
                        return;
                    }
                }
            }
        }
    }

    // ...(之后的部分)
}

// ...(其他类的定义)

我尝试了尽量简化代码。我在这个问题上进行了大量搜索并向许多人提问,但是没有得到我想要的答案。我不确定为什么找不到相关内容,但如果你能帮助我或者提供相关文章的链接,我将非常感激。

英文:

I had this object oriented programming project last semester and it was all about simulating a simple dormitory.

1.There should have been a manager class in which the main method and like 80 percent of the other methods had to be there.
2.A dormitory class containing an arraylist of blocks.
3.A block class containing an arraylist of rooms.
4.A room class containing an arraylist of students.
5.All of these classes contained getters and setters for their private variables.

There were a few methods that we should've added to the program which has nothing to do with my question,so I will not write them in here,but the thing is,a few of theses methods needed to look through these arraylists to find a specific object.For example,a student with a specific student number.I created these methods with nested loops.But I know there is some way I could avoid heavy nesting.

Here is my reduced code.I will only let the manager class contain one nested loop method as an example:

import java.util.Scanner;

public class Manager {

    private String name;
    private String familyName;
    private String userName;
    private String passWord;

    private static Scanner scan = new Scanner(System.in);
    private Dormitory dorm = new Dormitory();
    private static Menu menu = new Menu();
    private Student tempStudent;
    private Block tempBlock;
    private Room room;
    private boolean bool;

    {
        dorm.setDormManager(this);
    }

    public Manager(String managerName, String managerID) {
        name = managerName;
        userName = managerID;
    }

    //find student with its number
    public void findStudent() {
        //Taking the student number from the user.
        System.out.println("Please enter the student number:");
        String studentNum = scan.nextLine();
        for (int i = 0; i < dorm.getBlockList().size(); i++)
            for (int j = 0; j < dorm.getBlockList().get(i).getRooms().size(); j++)
                for (int k = 0; k < dorm.getBlockList().get(i).getRooms().get(j).getRoomStudents().size(); k++)
                    if (dorm.getBlockList().get(i).getRooms().get(j).getRoomStudents().get(k).getStudentNumber().equals(studentNum)) {
                        tempStudent = dorm.getBlockList().get(i).getRooms().get(j).getRoomStudents().get(k);
                        break;
                    }
    }

    public void create() {
        //Used loops for the original program.
        Block block1 = new Block("1");
        Block block2 = new Block("2");
        dorm.getBlockList().add(block1);
        dorm.getBlockList().add(block2);
        Room room1 = new Room("1");
        Room room2 = new Room("2");
        dorm.getBlockList().get(0).getRooms().add(room1);
        dorm.getBlockList().get(1).getRooms().add(room2);
        Student student1 = new Student("12345678");
        Student student2 = new Student("98765432");
        dorm.getBlockList().get(0).getRooms().get(0).getRoomStudents().add(student1);
        dorm.getBlockList().get(1).getRooms().get(0).getRoomStudents().add(student2);
    }

    public static void main(String[] args) {
        Manager manager = new Manager("Dumbledore", "@1112");
        manager.create();
    }
}

public class Dormitory {

    private int blocks;
    private Manager dormManager;
    private long allMembers;
    private ArrayList<Block> blockList = new ArrayList<Block>();
}

public class Block {

    private String blockNumber;
    private ArrayList<Room> rooms = new ArrayList<Room>();
    private Dormitory dorm = new Dormitory();

    public Block(String blockNum) {
        blockNumber = blockNum;
    }
}

public class Room {

    private String roomNumber;
    private ArrayList<Student> roomStudents = new ArrayList<Student>();
    private Block roomBlock;
    private Student roomManager;

    public Room(String roomNum) {
        roomNumber = roomNum;
    }
}

public class Student {

    private String studentName;
    private String studentFamilyName;
    private String studentNumber;
    private Room room;

    public Student(String studentNum) { //Creates a student object using the student number.
        studentNumber = studentNum;
    }
}

I tried my best to reduce the code.
I searched a lot and asked a lot of people about this but I didn't get my desired answer.I'm not sure why I couldn't find anything about this,but I'd really appreciate it if you'd lend me a hand or give me the link of a related article.

答案1

得分: 1

简短回答:不,你不应该通过循环遍历每个元素来检查 getStudentNumber().equals(studentNum)。这具有线性时间复杂度O(N)

详细回答:你应该根据查询对数据进行索引。

例如:使用具有常数时间复杂度O(1)的HashMap进行索引。(注意:此代码不是线程安全的)

public class SchoolService {
    private Map<String, Student> studentsById = new HashMap<>();
    private Map<Long, Dorm> dormsById = new HashMap<>();

    /// dormsByAreaCode 是一个将对象分组到列表中的索引示例
    private Map<String, List<Dorm>> dormsByAreaCode = new HashMap<>();

    public void addStudent(Student student) {
       if (studentsById.containsKey(student.getName()) {
           throw new IllegalStateException("Duplicate student " + student.getName());
       }
       studentsById.put(student.getId(), student);
    }

    public Student getStudentById(String studentId) {
       Student student = studentsById.get(studentId);
       if (student == null) {
           throw new IllegalStateException("No such student " + studentId);
       }
       return student;
    }

    public void addDorm(Dorm dorm) {
        // TODO: validation
        dormsById.put(dorm.getId(), dorm);
        List<Dorm> areaDorms = dormsByAreaCode.get(dorm.getAreaCode());
        if (areaDorms == null) {
            areaDorms = new ArrayList<>();
            dormsByAreaCode.put(dorm.getAreaCode(), areaDorms);
        }
        areaDorms.add(dorm);
    }

    public Dorm getDormById(long dormId) {
        Dorm dorm = dormsById.get(id);
        // TODO: validation
        return dorm;
    }

    public List<Dorm> getDormsByAreaCode(String areaCode) {
        List<Dorm> areaDorms = dormsByAreaCode.get(areaCode);
        // TODO: validation
        return areaDorms;
    }

    // 等等
}
英文:

Short answer: No, you should never loop through everything checking for getStudentNumber().equals(studentNum). This has linear time complexity O(N)

Long answer: You should index your data based on your queries

Eg: Indexing with HashMaps which have constant time complexity O(1). (Note: This code is not thread safe)

public class SchoolService {
private Map&lt;String, Student&gt; studentsById = new HashMap&lt;&gt;();
private Map&lt;Long, Dorm&gt; dormsById = new HashMap&lt;&gt;();
/// dormsByAreaCode is showing an example of an index which groups objects into lists
private Map&lt;String, List&lt;Dorm&gt;&gt; dormsByAreaCode = new HashMap&lt;&gt;();
public void addStudent(Student student) {
if (studentsById.containsKey(student.getName()) {
throw new IllegalStateException(&quot;Duplicate student &quot; + student.getName());
}
studentsById.put(student.getId(), student);
}
public Student getStudentById(String studentId) {
Student student = studentsById.get(studentId);
if (student == null) {
throw new IllegalStateException(&quot;No such student &quot; + studentId);
}
return student;
}
public void addDorm(Dorm dorm) {
// TODO: validation
dormsById.put(dorm.getId(), dorm);
List&lt;Dorm&gt; areaDorms = dormsByAreaCode.get(dorm.getAreaCode());
if (areaDorms == null) {
areaDorms = new ArrayList&lt;&gt;();
dormsByAreaCode.put(dorm.getAreaCode(), areaDorms);
}
areaDorms.add(dorm);
}
public Dorm getDormById(long dormId) {
Dorm dorm = dormsById.get(id);
// TODO: validation
return dorm;
}
public List&lt;Dorm&gt; getDormsByAreaCode(String areaCode) {
List&lt;Dorm&gt; areaDorms = dormsByAreaCode.get(areaCode);
// TODO: validation
return areaDorms;
}
// etc
}

答案2

得分: 0

以下引用来自tutorialspoint。这是Stream接口中forEach方法的完美用例。我提供的链接以及关于流的进一步阅读可以帮助避免重复的代码。
> 在Java中使用集合框架,开发人员必须使用循环并进行重复检查。另一个问题是效率;随着多核处理器容易获得,Java开发人员必须编写可以相当容易出错的并行代码处理。

dorm.getBlockList().stream().forEach((b) -&gt; {
b.getRooms().stream().forEach((r) -&gt; {
...
})
});

你还可以阅读关于parallelStream的内容在这里

英文:

The following quote is from tutorialspoint. This is the perfect use case of the forEach method from the Stream interface. The link I provided and further reading on Streams can help avoid repetitive code.
> Using collections framework in Java, a developer has to use loops and make repeated checks. Another concern is efficiency; as multi-core processors are available at ease, a Java developer has to write parallel code processing that can be pretty error-prone.

dorm.getBlockList().stream().forEach((b) -&gt; {
b.getRooms().stream().forEach((r) -&gt; {
...
})
});

You can also read about parallelStreams from here.

huangapple
  • 本文由 发表于 2020年9月13日 02:15:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/63863510.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定