Como iterar eficientemente cada entrada em um mapa Java?
Se eu tiver um objecto que implemente a interface Map
em Java e eu quiser iterar sobre cada par contido nele, Qual é a forma mais eficiente de percorrer o mapa?
a ordenação dos elementos dependerá da implementação do mapa específico que eu tenho para a interface?
30 answers
Map<String, String> map = ...
for (Map.Entry<String, String> entry : map.entrySet())
{
System.out.println(entry.getKey() + "/" + entry.getValue());
}
-
Usando iterator e Map.Entrada
long i = 0; Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Integer, Integer> pair = it.next(); i += pair.getKey() + pair.getValue(); }
-
Usando foreache Map.Entrada
long i = 0; for (Map.Entry<Integer, Integer> pair : map.entrySet()) { i += pair.getKey() + pair.getValue(); }
-
Utilizar forEach de Java 8
final long[] i = {0}; map.forEach((k, v) -> i[0] += k + v);
-
Usando keySet e foreach
long i = 0; for (Integer key : map.keySet()) { i += key + map.get(key); }
-
Usando keySet e iterator
long i = 0; Iterator<Integer> itr2 = map.keySet().iterator(); while (itr2.hasNext()) { Integer key = itr2.next(); i += key + map.get(key); }
-
Usando para e Mapa.Entrada
long i = 0; for (Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator(); entries.hasNext(); ) { Map.Entry<Integer, Integer> entry = entries.next(); i += entry.getKey() + entry.getValue(); }
-
Usando a API Java 8 Stream
final long[] i = {0}; map.entrySet().stream().forEach(e -> i[0] += e.getKey() + e.getValue());
-
Usando o paralelo Java 8 Stream API
final long[] i = {0}; map.entrySet().stream().parallel().forEach(e -> i[0] += e.getKey() + e.getValue());
-
Usando IterableMap de
Apache Collections
long i = 0; MapIterator<Integer, Integer> it = iterableMap.mapIterator(); while (it.hasNext()) { i += it.next() + it.getValue(); }
-
Usando o MutableMap das colecções Eclipse (CS)
final long[] i = {0}; mutableMap.forEachKeyValue((key, value) -> { i[0] += key + value; });
Testes de Perfomance (Modo = Tempo Médio, sistema = Windows 8.1 64-bit, Intel i7-4790 3.60 GHz, 16 GB)
-
Para um mapa pequeno (100 elementos), a pontuação 0, 388 é a melhor
Benchmark Mode Cnt Score Error Units test3_UsingForEachAndJava8 avgt 10 0.308 ± 0.021 µs/op test10_UsingEclipseMap avgt 10 0.309 ± 0.009 µs/op test1_UsingWhileAndMapEntry avgt 10 0.380 ± 0.014 µs/op test6_UsingForAndIterator avgt 10 0.387 ± 0.016 µs/op test2_UsingForEachAndMapEntry avgt 10 0.391 ± 0.023 µs/op test7_UsingJava8StreamApi avgt 10 0.510 ± 0.014 µs/op test9_UsingApacheIterableMap avgt 10 0.524 ± 0.008 µs/op test4_UsingKeySetAndForEach avgt 10 0.816 ± 0.026 µs/op test5_UsingKeySetAndIterator avgt 10 0.863 ± 0.025 µs/op test8_UsingJava8StreamApiParallel avgt 10 5.552 ± 0.185 µs/op
-
Para um mapa com 10000 elementos, a pontuação 37.606 é a melhor
Benchmark Mode Cnt Score Error Units test10_UsingEclipseMap avgt 10 37.606 ± 0.790 µs/op test3_UsingForEachAndJava8 avgt 10 50.368 ± 0.887 µs/op test6_UsingForAndIterator avgt 10 50.332 ± 0.507 µs/op test2_UsingForEachAndMapEntry avgt 10 51.406 ± 1.032 µs/op test1_UsingWhileAndMapEntry avgt 10 52.538 ± 2.431 µs/op test7_UsingJava8StreamApi avgt 10 54.464 ± 0.712 µs/op test4_UsingKeySetAndForEach avgt 10 79.016 ± 25.345 µs/op test5_UsingKeySetAndIterator avgt 10 91.105 ± 10.220 µs/op test8_UsingJava8StreamApiParallel avgt 10 112.511 ± 0.365 µs/op test9_UsingApacheIterableMap avgt 10 125.714 ± 1.935 µs/op
-
Para um mapa com 100000 elementos, a pontuação 1184.767 é a best
Benchmark Mode Cnt Score Error Units test1_UsingWhileAndMapEntry avgt 10 1184.767 ± 332.968 µs/op test10_UsingEclipseMap avgt 10 1191.735 ± 304.273 µs/op test2_UsingForEachAndMapEntry avgt 10 1205.815 ± 366.043 µs/op test6_UsingForAndIterator avgt 10 1206.873 ± 367.272 µs/op test8_UsingJava8StreamApiParallel avgt 10 1485.895 ± 233.143 µs/op test5_UsingKeySetAndIterator avgt 10 1540.281 ± 357.497 µs/op test4_UsingKeySetAndForEach avgt 10 1593.342 ± 294.417 µs/op test3_UsingForEachAndJava8 avgt 10 1666.296 ± 126.443 µs/op test7_UsingJava8StreamApi avgt 10 1706.676 ± 436.867 µs/op test9_UsingApacheIterableMap avgt 10 3289.866 ± 1445.564 µs/op
Gráficos (testes de perfeição dependendo do tamanho do mapa)
Tabela (testes de perfomância dependendo do tamanho do mapa)
100 600 1100 1600 2100
test10 0.333 1.631 2.752 5.937 8.024
test3 0.309 1.971 4.147 8.147 10.473
test6 0.372 2.190 4.470 8.322 10.531
test1 0.405 2.237 4.616 8.645 10.707
test2 0.376 2.267 4.809 8.403 10.910
test7 0.473 2.448 5.668 9.790 12.125
test9 0.565 2.830 5.952 13.220 16.965
test4 0.808 5.012 8.813 13.939 17.407
test5 0.810 5.104 8.533 14.064 17.422
test8 5.173 12.499 17.351 24.671 30.403
Todos os testes estão emGitHub .
Em Java 8 Você pode fazê-lo limpo e rápido usando as novas características lambdas:
Map<String,String> map = new HashMap<>();
map.put("SomeKey", "SomeValue");
map.forEach( (k,v) -> [do something with key and value] );
// such as
map.forEach( (k,v) -> System.out.println("Key: " + k + ": Value: " + v));
O tipo de k
e v
será inferido pelo compilador e não há mais necessidade de usar Map.Entry
.
Sim, a ordem depende da implementação do mapa específico.
@ScArcher2 tem a sintaxe Java 1.5 mais elegante . Em 1.4, eu faria algo assim:
Iterator entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
Entry thisEntry = (Entry) entries.next();
Object key = thisEntry.getKey();
Object value = thisEntry.getValue();
// ...
}
O código típico para iterar sobre um mapa é:
Map<String,Thing> map = ...;
for (Map.Entry<String,Thing> entry : map.entrySet()) {
String key = entry.getKey();
Thing thing = entry.getValue();
...
}
HashMap
é a implementação canônica do mapa e não faz garantias (ou ainda que não deve mudar a ordem se nenhuma operação de mutação é realizada nele). SortedMap
irá devolver as entradas com base na ordenação natural das chaves, ou um Comparator
, Se for fornecido. LinkedHashMap
irá devolver as entradas na ordem de inserção ou na ordem de acesso, dependendo de como foi construído. EnumMap
devolve os itens na ordem natural de chave.
(atualização: eu acho que isso já não é verdade.([18]}) Nota, IdentityHashMap
entrySet
o iterator tem actualmente uma implementação peculiar que devolve a mesma instância Map.Entry
para cada item do entrySet
! No entanto, sempre que um novo iterador avança, o Map.Entry
é actualizado.
Exemplo de Utilização do iterator e dos genéricos:
Iterator<Map.Entry<String, String>> entries = myMap.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, String> entry = entries.next();
String key = entry.getKey();
String value = entry.getValue();
// ...
}
como iterar sobre as entradas de um mapa - @ScArcher2 respondeuisso perfeitamente.
Qual é a ordem de iteração - Se você está apenas usando {[[0]}, então estritamente falando, não há nenhuma garantia de ordenação {[[24]}. Então você não deve realmente confiar na ordenação dada por qualquer implementação. No entanto, a SortedMap
a interface extende Map
e fornece exactamente o que procura - as implementações darão uma ordem de ordenação consistente.
NavigableMap
is another useful extension - this is a SortedMap
with additional methods for finding entries by their ordered position in the key set. Portanto, potencialmente isto pode remover a necessidade de iteração em primeiro lugar-você pode ser capaz de encontrar o entry
específico que você está depois de usar o higherEntry
, lowerEntry
, ceilingEntry
, quer floorEntry
métodos. O método descendingMap
até lhe dá um método explícito de reverter a ordem transversal.
Aqui está a comparação das suas performances para um conjunto de dados comum armazenado no mapa, armazenando um milhão de pares de valores-chave no mapa e irá iterar sobre o mapa.
1) Utilizar entrySet()
em cada ciclo
for (Map.Entry<String,Integer> entry : testMap.entrySet()) {
entry.getKey();
entry.getValue();
}
50 milisegundos
2) Utilizar keySet()
em cada ciclo
for (String key : testMap.keySet()) {
testMap.get(key);
}
76 milisegundos
3) Utilizar entrySet()
e iterador
Iterator<Map.Entry<String,Integer>> itr1 = testMap.entrySet().iterator();
while(itr1.hasNext()) {
Map.Entry<String,Integer> entry = itr1.next();
entry.getKey();
entry.getValue();
}
50 milisegundos
4) Utilizar keySet()
e iterator
Iterator itr2 = testMap.keySet().iterator();
while(itr2.hasNext()) {
String key = itr2.next();
testMap.get(key);
}
75 milisegundos
Já me referi this link
.
Para que saibas, também podes usar map.keySet()
e map.values()
se só estiveres interessado em chaves/valores do mapa e não no outro.
A forma correcta de o fazer é usar a resposta aceite, pois é a mais eficiente. Acho que o seguinte código parece mais limpo.
for (String key: map.keySet()) {
System.out.println(key + "/" + map.get(key));
}
Com Eclipse Collections (anteriormente GS Collections ), você usaria o método forEachKeyValue na interface MapIterable , que é herdada pelas interfaces MutableMap e ImmutableMap e suas implementações.
final MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue(new Procedure2<Integer, String>()
{
public void value(Integer key, String value)
{
result.add(key + value);
}
});
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);
Com a sintaxe Java 8 lambda, você pode escrever o código da seguinte forma:
MutableBag<String> result = Bags.mutable.empty();
MutableMap<Integer, String> map = Maps.mutable.of(1, "One", 2, "Two", 3, "Three");
map.forEachKeyValue((key, value) -> result.add(key + value));
Assert.assertEquals(Bags.mutable.of("1One", "2Two", "3Three"), result);
Nota: Eu sou um committer para coleções de Eclipse.
Tenta isto com Java 1.4:
for( Iterator entries = myMap.entrySet().iterator(); entries.hasNext();){
Entry entry = (Entry) entries.next();
System.out.println(entry.getKey() + "/" + entry.getValue());
//...
}
map.entrySet()
, que devolve um conjunto de Map.Entry
, cada um dos quais contém uma chave e um valor (entry.getKey()
e entry.getValue()
).
Numa implementação idiossincrática, pode fazer alguma diferença se usar map.keySet()
, map.entrySet()
ou outra coisa qualquer. Mas não consigo pensar numa razão para alguém O escrever assim. O mais provável é que não faça diferença o que você faz.
E sim, a ordem dependerá da implementação - assim como (possivelmente) da ordem de inserção e de outros fatores difíceis de controlar.
[editar] eu escrevi valueSet()
originalmente, mas é claro entrySet()
é realmente a resposta.
Java 8:
Pode usar expressões lambda:
myMap.entrySet().stream().forEach((entry) -> {
Object currentKey = entry.getKey();
Object currentValue = entry.getValue();
});
Para mais informações, siga Este.
Lambda Expressão Java 8
Em Java 1.8 (Java 8) isto tornou-se muito mais fácil usando o método forEach a partir de operações agregadas(operações de fluxo) que parecem semelhantes aos iteradores da Interface Iterable.
Basta copiar a pasta abaixo da declaração para o seu código e mudar o nome da variável HashMap de hm para a sua variável HashMap para imprimir o par de valores-chave.
HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>();
/*
* Logic to put the Key,Value pair in your HashMap hm
*/
// Print the key value pair in one line.
hm.forEach((k,v) -> System.out.println("key: "+k+" value:"+v));
// Just copy and paste above line to your code.
Abaixo está o código da amostra que i tentou usar a expressão Lambda . Isto é tão fixe. Tenho de tentar.
HashMap<Integer,Integer> hm = new HashMap<Integer, Integer>();
Random rand = new Random(47);
int i=0;
while(i<5){
i++;
int key = rand.nextInt(20);
int value = rand.nextInt(50);
System.out.println("Inserting key: "+key+" Value: "+value);
Integer imap =hm.put(key,value);
if( imap == null){
System.out.println("Inserted");
}
else{
System.out.println("Replaced with "+imap);
}
}
hm.forEach((k,v) -> System.out.println("key: "+k+" value:"+v));
Output:
Inserting key: 18 Value: 5
Inserted
Inserting key: 13 Value: 11
Inserted
Inserting key: 1 Value: 29
Inserted
Inserting key: 8 Value: 0
Inserted
Inserting key: 2 Value: 7
Inserted
key: 1 value:29
key: 18 value:5
key: 2 value:7
key: 8 value:0
key: 13 value:11
Também se pode usar O separador para o mesmo.
Spliterator sit = hm.entrySet().spliterator();
Actualizar
Incluindo ligações de documentação aos documentos da Oracle. Para mais em Lambda ir para estelink e deve leroperações agregadas e para o separador ir para estelink .
No mapa pode-se iterar sobre keys
e/ou values
e/ou both (e.g., entrySet)
depende de se estar interessado em:
1.) Iterar através da keys -> keySet()
do mapa:
Map<String, Object> map = ...;
for (String key : map.keySet()) {
//your Business logic...
}
2.) Iterar através da values -> values()
do mapa:
for (Object value : map.values()) {
//your Business logic...
}
3.) Iterar através da both -> entrySet()
do mapa:
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
//your Business logic...
}
além disso, existem 3 maneiras diferentes de iterar através de um HashMap. São como abaixo_
//1.
for (Map.Entry entry : hm.entrySet()) {
System.out.print("key,val: ");
System.out.println(entry.getKey() + "," + entry.getValue());
}
//2.
Iterator iter = hm.keySet().iterator();
while(iter.hasNext()) {
Integer key = (Integer)iter.next();
String val = (String)hm.get(key);
System.out.println("key,val: " + key + "," + val);
}
//3.
Iterator it = hm.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
Integer key = (Integer)entry.getKey();
String val = (String)entry.getValue();
System.out.println("key,val: " + key + "," + val);
}
public class abcd{
public static void main(String[] args)
{
Map<Integer, String> testMap = new HashMap<Integer, String>();
testMap.put(10, "a");
testMap.put(20, "b");
testMap.put(30, "c");
testMap.put(40, "d");
for (Integer key:testMap.keySet()) {
String value=testMap.get(key);
System.out.println(value);
}
}
}
Ou
public class abcd {
public static void main(String[] args)
{
Map<Integer, String> testMap = new HashMap<Integer, String>();
testMap.put(10, "a");
testMap.put(20, "b");
testMap.put(30, "c");
testMap.put(40, "d");
for (Entry<Integer, String> entry : testMap.entrySet()) {
Integer key=entry.getKey();
String value=entry.getValue();
}
}
}
Se tem um mapa não tipado genérico, pode usar:
Map map = new HashMap();
for (Map.Entry entry : ((Set<Map.Entry>) map.entrySet())) {
System.out.println(entry.getKey() + "/" + entry.getValue());
}
Com Java 8
map.forEach((k, v) -> System.out.println((k + ":" + v)));
Mais compacto com Java 8:
map.entrySet().forEach(System.out::println);
Iterator iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry element = (Map.Entry)it.next();
LOGGER.debug("Key: " + element.getKey());
LOGGER.debug("value: " + element.getValue());
}
Pode fazê-lo usando genéricos:
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<Integer, Integer> entry = entries.next();
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
Iterator itr2 = testMap.keySet().iterator();
while (itr2.hasNext()) {
String key = itr2.next();
testMap.get(key);
}
for (String key: map.keySet()) {
System.out.println(key + "/" + map.get(key));
}
A melhor maneira é entrySet()
no entanto.
Na Java 8 temos o método forEach
que aceita uma expressão lambda . Nós também temos APIsstream. Considere um mapa:
Map<String,String> sample = new HashMap<>();
sample.put("A","Apple");
sample.put("B", "Ball");
Iterar sobre as chaves:
sample.keySet().forEach((k) -> System.out.println(k));
Iterar sobre os valores:
sample.values().forEach((v) -> System.out.println(v));
Iterar sobre os itens (usando forEach e Streams):
sample.forEach((k,v) -> System.out.println(k + "=" + v));
sample.entrySet().stream().forEach((entry) -> {
Object currentKey = entry.getKey();
Object currentValue = entry.getValue();
System.out.println(currentKey + "=" + currentValue);
});
A vantagem com os fluxos é que eles podem ser paralelos facilmente, caso queiramos. Nós simplesmente precisamos usar parallelStream()
no lugar de stream()
acima.
//Functional Oprations
Map<String, String> mapString = new HashMap<>();
mapString.entrySet().stream().map((entry) -> {
String mapKey = entry.getKey();
return entry;
}).forEach((entry) -> {
String mapValue = entry.getValue();
});
//Intrator
Map<String, String> mapString = new HashMap<>();
for (Iterator<Map.Entry<String, String>> it = mapString.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, String> entry = it.next();
String mapKey = entry.getKey();
String mapValue = entry.getValue();
}
//Simple for loop
Map<String, String> mapString = new HashMap<>();
for (Map.Entry<String, String> entry : mapString.entrySet()) {
String mapKey = entry.getKey();
String mapValue = entry.getValue();
}
package com.test;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class Test {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("ram", "ayodhya");
map.put("krishan", "mathura");
map.put("shiv", "kailash");
System.out.println("********* Keys *********");
Set<String> keys = map.keySet();
for (String key : keys) {
System.out.println(key);
}
System.out.println("********* Values *********");
Collection<String> values = map.values();
for (String value : values) {
System.out.println(value);
}
System.out.println("***** Keys and Values (Using for each loop) *****");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("Key: " + entry.getKey() + "\t Value: "
+ entry.getValue());
}
System.out.println("***** Keys and Values (Using while loop) *****");
Iterator<Entry<String, String>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, String> entry = (Map.Entry<String, String>) entries
.next();
System.out.println("Key: " + entry.getKey() + "\t Value: "
+ entry.getValue());
}
System.out
.println("** Keys and Values (Using java 8 using lambdas )***");
map.forEach((k, v) -> System.out
.println("Key: " + k + "\t value: " + v));
}
}
Sim, como muitas pessoas concordaram esta é a melhor maneira de iterar sobre um Map
.
Mas há hipóteses de atirar nullpointerexception
se o mapa for null
. Não se esqueça de colocar null
.verificar.
|
|
- - - -
|
|
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
}
Map<String, Integer> m = new HashMap<String, Integer>();
Então você pode fazer algo como o abaixo para iterar sobre os elementos do mapa.
// ********** Using an iterator ****************
Iterator<Entry<String, Integer>> me = m.entrySet().iterator();
while(me.hasNext()){
Entry<String, Integer> pair = me.next();
System.out.println(pair.getKey() + ":" + pair.getValue());
}
// *********** Using foreach ************************
for(Entry<String, Integer> me : m.entrySet()){
System.out.println(me.getKey() + " : " + me.getValue());
}
// *********** Using keySet *****************************
for(String s : m.keySet()){
System.out.println(s + " : " + m.get(s));
}
// *********** Using keySet and iterator *****************
Iterator<String> me = m.keySet().iterator();
while(me.hasNext()){
String key = me.next();
System.out.println(key + " : " + m.get(key));
}
Utilizar Java 8:
map.entrySet().forEach(entry -> System.out.println(entry.getValue()));
A encomenda dependerá sempre da implementação específica do mapa. Usando Java 8 Você pode usar qualquer um destes:
map.forEach((k,v) -> { System.out.println(k + ":" + v); });
Ou:
map.entrySet().forEach((e) -> {
System.out.println(e.getKey() + " : " + e.getValue());
});
O resultado será o mesmo (mesma ordem). O entrySet apoiado pelo mapa para que você está recebendo a mesma ordem. O segundo é útil, pois permite-lhe usar lambdas, por exemplo, se quiser imprimir apenas objectos inteiros que sejam superiores a 5:
map.entrySet()
.stream()
.filter(e-> e.getValue() > 5)
.forEach(System.out::println);
O código abaixo mostra a iteração através do LinkedHashMap e do HashMap normal (exemplo). Você verá a diferença na ordem:
public class HMIteration {
public static void main(String[] args) {
Map<Object, Object> linkedHashMap = new LinkedHashMap<>();
Map<Object, Object> hashMap = new HashMap<>();
for (int i=10; i>=0; i--) {
linkedHashMap.put(i, i);
hashMap.put(i, i);
}
System.out.println("LinkedHashMap (1): ");
linkedHashMap.forEach((k,v) -> { System.out.print(k + " (#="+k.hashCode() + "):" + v + ", "); });
System.out.println("\nLinkedHashMap (2): ");
linkedHashMap.entrySet().forEach((e) -> {
System.out.print(e.getKey() + " : " + e.getValue() + ", ");
});
System.out.println("\n\nHashMap (1): ");
hashMap.forEach((k,v) -> { System.out.print(k + " (#:"+k.hashCode() + "):" + v + ", "); });
System.out.println("\nHashMap (2): ");
hashMap.entrySet().forEach((e) -> {
System.out.print(e.getKey() + " : " + e.getValue() + ", ");
});
}
}
LinkedHashMap (1):
10 (#=10):10, 9 (#=9):9, 8 (#=8):8, 7 (#=7):7, 6 (#=6):6, 5 (#=5):5, 4 (#=4):4, 3 (#=3):3, 2 (#=2):2, 1 (#=1):1, 0 (#=0):0,
LinkedHashMap (2):
10 : 10, 9 : 9, 8 : 8, 7 : 7, 6 : 6, 5 : 5, 4 : 4, 3 : 3, 2 : 2, 1 : 1, 0 : 0,
HashMap (1):
0 (#:0):0, 1 (#:1):1, 2 (#:2):2, 3 (#:3):3, 4 (#:4):4, 5 (#:5):5, 6 (#:6):6, 7 (#:7):7, 8 (#:8):8, 9 (#:9):9, 10 (#:10):10,
HashMap (2):
0 : 0, 1 : 1, 2 : 2, 3 : 3, 4 : 4, 5 : 5, 6 : 6, 7 : 7, 8 : 8, 9 : 9, 10 : 10,