杰瑞科技汇

Java List中如何高效处理List嵌套?

Of course! In Java, a "list in a list" is typically implemented using a List of List objects. The most common and flexible way to do this is with a List<List<E>>, where E is the type of elements you want to store in the inner lists.

Java List中如何高效处理List嵌套?-图1
(图片来源网络,侵删)

Here’s a comprehensive guide covering:

  1. How to Declare and Initialize
  2. How to Add Elements
  3. How to Access Elements
  4. Common Operations (Iteration, Removal, etc.)
  5. Practical Example: A Student-Grade System
  6. When to Use This Structure
  7. Important Considerations

How to Declare and Initialize

You declare it just like any other generic type. For initialization, you should almost always use the ArrayList implementation, which is a good default choice.

import java.util.ArrayList;
import java.util.List;
// Declaration
List<List<String>> listOfLists;
// Initialization
listOfLists = new ArrayList<>(); // This creates a list that will hold other lists.

Best Practice: Initialize Inner Lists on the Fly

When you add a new inner list to your main list, you must create it first.

// Create the outer list
List<List<Integer>> matrix = new ArrayList<>();
// Create the first inner list and add it to the outer list
List<Integer> row1 = new ArrayList<>();
row1.add(1);
row1.add(2);
row1.add(3);
matrix.add(row1);
// Create the second inner list and add it
List<Integer> row2 = new ArrayList<>();
row2.add(4);
row2.add(5);
row2.add(6);
matrix.add(row2);
// Now, matrix looks like this: [[1, 2, 3], [4, 5, 6]]

How to Add Elements

You have two main operations:

Java List中如何高效处理List嵌套?-图2
(图片来源网络,侵删)
  • Adding a whole new list to the outer list.
  • Adding an element to one of the inner lists.
List<String> fruits = new ArrayList<>();
List<String> vegetables = new ArrayList<>();
// Add elements to the inner lists
fruits.add("Apple");
fruits.add("Banana");
vegetables.add("Carrot");
vegetables.add("Broccoli");
// Create the outer list and add the inner lists to it
List<List<String>> groceryListByCategory = new ArrayList<>();
groceryListByCategory.add(fruits);      // Adds the "fruits" list
groceryListByCategory.add(vegetables); // Adds the "vegetables" list
// groceryListByCategory is now: [["Apple", "Banana"], ["Carrot", "Broccoli"]]

How to Access Elements

Accessing elements is a two-step process using get():

  1. Get the inner list from the outer list using its index.
  2. Get the element from the inner list using its index.
// Continuing from the example above...
// Access the second category (index 1)
List<String> secondCategory = groceryListByCategory.get(1); // This is ["Carrot", "Broccoli"]
// Access the first item in the second category (index 0)
String firstVegetable = secondCategory.get(0); // This is "Carrot"
// You can also chain the calls for a one-off access
String secondFruit = groceryListByCategory.get(0).get(1); // This is "Banana"

Common Operations

Iterating with a for-each Loop (Most Common)

This is the cleanest way to loop through all elements.

List<List<Integer>> matrix = List.of(
    List.of(1, 2, 3),
    List.of(4, 5, 6),
    List.of(7, 8, 9)
);
// Outer loop iterates through each inner list
for (List<Integer> row : matrix) {
    // Inner loop iterates through each element in the current inner list
    for (Integer number : row) {
        System.out.print(number + " "); // Prints: 1 2 3 4 5 6 7 8 9
    }
    System.out.println(); // For a new line after each row
}

Getting the Size

  • size() on the outer list gives you the number of inner lists.
  • size() on an inner list gives you the number of elements in that specific list.
System.out.println("Number of categories: " + groceryListByCategory.size()); // Output: 2
System.out.println("Number of fruits: " + groceryListByCategory.get(0).size()); // Output: 2

Removing Elements

You can remove either an entire inner list or an element from within an inner list.

// Remove an entire inner list (e.g., the vegetables list)
groceryListByCategory.remove(1); // Removes the list at index 1
// Now groceryListByCategory is just: [["Apple", "Banana"]]
// Remove a specific element from an inner list
groceryListByCategory.get(0).remove("Apple"); // Removes "Apple" from the first list
// Now groceryListByCategory is: [["Banana"]]

Practical Example: A Student-Grade System

Imagine you want to store a student's name and a list of their grades.

import java.util.ArrayList;
import java.util.List;
public class StudentGradeSystem {
    public static void main(String[] args) {
        // The main list will hold all student records
        List<List<Object>> studentRecords = new ArrayList<>();
        // --- Add Student 1 ---
        List<Object> student1 = new ArrayList<>();
        student1.add("Alice");
        student1.add(20); // Age
        student1.add(List.of(95, 88, 91)); // Grades
        studentRecords.add(student1);
        // --- Add Student 2 ---
        List<Object> student2 = new ArrayList<>();
        student2.add("Bob");
        student2.add(21);
        student2.add(List.of(76, 85, 80));
        studentRecords.add(student2);
        // --- Access and Print Data ---
        System.out.println("--- Student Records ---");
        for (List<Object> record : studentRecords) {
            String name = (String) record.get(0);
            int age = (Integer) record.get(1);
            List<Integer> grades = (List<Integer>) record.get(2);
            System.out.println("Name: " + name);
            System.out.println("Age: " + age);
            System.out.println("Grades: " + grades);
            System.out.println("----------------------");
        }
        // --- Calculate and Print Average Grade for Alice ---
        List<Object> alicesRecord = studentRecords.get(0);
        List<Integer> alicesGrades = (List<Integer>) alicesRecord.get(2);
        double sum = 0;
        for (int grade : alicesGrades) {
            sum += grade;
        }
        double average = sum / alicesGrades.size();
        System.out.println("Alice's average grade: " + average);
    }
}

Output:

--- Student Records ---
Name: Alice
Age: 20
Grades: [95, 88, 91]
----------------------
Name: Bob
Age: 21
Grades: [76, 85, 80]
----------------------
Alice's average grade: 88.0

When to Use This Structure

A List<List<E>> is perfect for representing:

  • 2D Grids or Matrices: Like a spreadsheet, a tic-tac-toe board, or pixel data for an image.
  • Tabular Data: Where each inner list represents a row and the elements in that list represent the columns.
  • Grouped or Categorized Data: As shown in the grocery example, where each inner list is a category.
  • Multi-level Hierarchies: A simple representation of parent-child relationships (e.g., a list of departments, where each department is a list of employees).

Important Considerations

Type Safety with Generics

Using List<List<String>> is much better than List<List> or List<Object>. It provides compile-time type checking, preventing you from accidentally adding an integer to a list that should only contain strings.

Performance

  • Random Access: Both ArrayList and LinkedList provide O(1) time complexity for getting an element by its index (get(i)). So, accessing matrix.get(5).get(2) is very fast.
  • Insertions/Deletions:
    • Adding or removing an entire inner list from the middle of the outer ArrayList is slow (O(n)) because it requires shifting all subsequent elements.
    • Adding or removing elements from an inner ArrayList in the middle is also slow (O(n)).
    • If you need frequent insertions/deletions in the middle, consider using LinkedList for the outer or inner lists, but be aware of the performance trade-offs for get() operations.

"Varying Length" Inner Lists

A List<List<E>> is great, but if your inner lists can have different lengths, be careful when you assume they are all the same size (e.g., when iterating).

List<List<Integer>> irregularMatrix = new ArrayList<>();
irregularMatrix.add(List.of(1, 2));
irregularMatrix.add(List.of(3, 4, 5, 6));
// This loop is safe
for (List<Integer> row : irregularMatrix) {
    for (Integer num : row) {
        System.out.print(num + " ");
    }
}
// Output: 1 2 3 4 5 6
// This loop is NOT safe because it assumes all rows have 2 elements
// for (int i = 0; i < irregularMatrix.size(); i++) {
//     System.out.println(irregularMatrix.get(i).get(2)); // Throws IndexOutOfBoundsException on the second row
// }

The Modern Java 9+ List.of()

For creating immutable lists (lists that cannot be changed after creation), List.of() is a fantastic and concise tool.

// Creates an immutable outer list containing two immutable inner lists
List<List<String>> immutableMatrix = List.of(
    List.of("A", "B"),
    List.of("C", "D", "E")
);
// This will cause an UnsupportedOperationException
// immutableMatrix.add(List.of("F")); 
// This will also cause an UnsupportedOperationException
// immutableMatrix.get(0).add("Z");
分享:
扫描分享到社交APP
上一篇
下一篇