將列表的前 n 個元素放入數組中
1. 概述
當我們使用 Java 編程時,無縫操作數據的能力是一項重要技能。我們可能會遇到這樣的場景:需要從List
中提取特定數量的元素並將它們存儲在數組中。
在本教程中,我們將探討從List
中檢索前 n 個元素並將它們轉換為 Java 數組的步驟。
2.問題介紹
像往常一樣,讓我們通過示例來理解問題。假設我們有一個包含七個字符串的列表:
List<String> INPUT_LIST = Lists.newArrayList("one", "two", "three", "four", "five", "six", "seven");
int n = 5;
現在,我們想要獲取前n
(n=5)
個元素並將它們轉換為字符串數組。當然,這五個元素應該保留原始列表中的順序:
"one", "two", "three", "four", "five"
在本教程中,我們將探索實現目標的不同方法。為簡單起見,我們假設給定的n
不會大於列表的大小。此外,我們將使用單元測試斷言來驗證每個方法是否產生預期結果。
接下來,讓我們深入研究代碼。
3.使用for
循環
解決這個問題的一個簡單的想法是首先創建一個長度為n
空數組,然後循環遍歷列表中的前n
個元素並依次填充準備好的數組。
接下來,讓我們使用for
循環來實現這個想法:
String[] result = new String[n];
for (int i = 0; i < n; i++) {
result[i] = INPUT_LIST.get(i);
}
assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result);
上面的代碼非常容易理解。它完成了這項工作。
在我們的示例中,列表是ArrayList.
顧名思義, ArrayList
由數組支持。因此, ArrayList's
隨機訪問複雜度為O(1)
.
換句話說,調用ArrayList's get(i)
方法是高性能的。
然而,並非所有List
實現都提供O(1)
隨機訪問。例如, LinkedList
總是從第一個節點導航到所需的節點。因此,它的隨機訪問成本是O(n)
。
由於我們沒有解決ArrayList特定的問題,因此讓我們稍微改進一下我們的代碼。
由於我們需要從第一個元素迭代到第 n 個元素,因此我們可以使用Iterator
來獲取每個元素,而不是調用get()
方法,以避免隨機訪問調用:
String[] result2 = new String[n];
Iterator<String> iterator = INPUT_LIST.iterator();
for (int i = 0; i < n && iterator.hasNext(); i++) {
result2[i] = iterator.next();
}
assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result2);
4. 使用subList()
方法
我們已經看到了基於for
循環的解決方案。解決問題的另一個想法是將其分為兩部分:
- 獲取前n個元素
- 將提取的元素轉換為數組
List
接口提供了subList()
方法,它允許我們從列表對像中檢索連續元素。所以第一部分很容易使用INPUT_LIST.subList(0, n)
。
對於第二部分,我們可以通過多種方式將列表轉換為數組。接下來,讓我們以它們為例。
首先,讓我們將準備好的數組傳遞給List.toArray()
方法:
String[] result = new String[n];
INPUT_LIST.subList(0, n)
.toArray(result);
assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result);
正如我們所看到的,如果傳遞給toArray
() 方法的數組參數有足夠的空間容納列表(在本例中為子列表)中的元素,則toArray()
方法將使用列表元素填充數組。
但是,如果數組參數沒有足夠的空間容納列表元素, toArray()
會分配一個包含列表元素的新數組:
String[] result2 = INPUT_LIST.subList(0, n)
.toArray(new String[0]);
assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result2);
正如上面的代碼所示,我們沒有分配一個長度為n
數組。相反,當我們調用toArray()
方法時,我們傳遞“ new String[0]
”作為參數。結果, toArray()
創建並返回一個由列表元素填充的新數組。
如果我們使用 Java 11 或更高版本,我們可以將生成器函數傳遞給toArray()
方法:
// available only for java 11+
String[] result3 = INPUT_LIST.subList(0, n)
.toArray(String[]::new);
assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result3);
正如我們所看到的,我們只需要為生成器函數創建一個新的數組實例,僅此而已。因此,我們使用String[]'s
構造函數的方法引用作為生成器函數。
5. 使用流API
此外,我們可以使用 Stream API 來解決該問題。 Stream API是Java 8給我們帶來的一個重要的新特性。因此,它僅適用於 Java 8 或更高版本:
String[] result = INPUT_LIST.stream()
.limit(n)
.toArray(String[]::new);
assertArrayEquals(new String[] { "one", "two", "three", "four", "five" }, result);
在上面的示例中,我們使用limit(n)
方法使Stream
僅n
**源INPUT_LIST
中的前 n 個元素。然後,我們調用Stream
的toArray()
方法將流對象轉換為數組。與 Java 11 的List.toArray()
類似, Stream.toArray()
接受生成器函數**。因此,我們再次將“String[]::new”
傳遞給該方法並獲得了預期的數組。
六,結論
在本文中,我們通過示例探索了從列表中提取前n
個元素並將它們轉換為數組的不同方法。
與往常一樣,示例的完整源代碼可在 GitHub 上獲取。