Java LinkedHashMap получить первую или последнюю запись
я использовал LinkedHashMap
потому что важно, в каком порядке ключи введены на карте.
но теперь я хочу получить значение ключа в первую очередь (первая запись) или последний.
должен ли быть такой метод, как first()
и last()
или что-то подобное?
нужно ли мне иметь итератор, чтобы просто получить первую ключевую запись? Вот почему я использовал LinkedHashMap
!
спасибо!
12 ответов
семантика LinkedHashMap
по-прежнему являются таковыми карты, а не LinkedList
. Он сохраняет порядок вставки, да, но это деталь реализации, а не его интерфейс.
самый быстрый способ получить "первую" запись еще entrySet().iterator().next()
. Получение" последней " записи возможно, но повлечет за собой итерацию по всему набору записей, вызвав .next()
пока вы не дойдете до последнего. while (iterator.hasNext()) { lastElement = iterator.next() }
редактировать: однако, если вы готовы выходите за рамки API JavaSE,Коллекции Apache Commons своя LinkedMap
реализация, которая имеет такие методы, как firstKey
и lastKey
, которые делают то, что вы ищете. Интерфейс значительно богаче.
можете ли вы попробовать сделать что-то вроде (чтобы получить последнюю запись):
linkedHashMap.entrySet().toArray()[linkedHashMap.size() -1];
Это O (N) :)
LinkedHashMap
текущая реализация (Java 8)отслеживает ее хвост. Если производительность является проблемой и / или карта имеет большой размер, вы можете получить доступ к этому полю через отражение.
поскольку реализация может измениться, вероятно, неплохо иметь резервную стратегию. Возможно, вы захотите зарегистрировать что-то, если будет создано исключение, чтобы вы знали, что реализация изменилась.
Это может выглядеть так:
public static <K, V> Entry<K, V> getFirst(Map<K, V> map) {
if (map.isEmpty()) return null;
return map.entrySet().iterator().next();
}
public static <K, V> Entry<K, V> getLast(Map<K, V> map) {
try {
if (map instanceof LinkedHashMap) return getLastViaReflection(map);
} catch (Exception ignore) { }
return getLastByIterating(map);
}
private static <K, V> Entry<K, V> getLastByIterating(Map<K, V> map) {
Entry<K, V> last = null;
for (Entry<K, V> e : map.entrySet()) last = e;
return last;
}
private static <K, V> Entry<K, V> getLastViaReflection(Map<K, V> map) throws NoSuchFieldException, IllegalAccessException {
Field tail = map.getClass().getDeclaredField("tail");
tail.setAccessible(true);
return (Entry<K, V>) tail.get(map);
}
еще один способ получить первую и последнюю запись LinkedHashMap-использовать метод" toArray " интерфейса Set.
но я думаю, что итерация по записям в наборе записей и получение первой и последней записи-лучший подход.
использование методов массива приводит к предупреждению формы " ...необходимо unchecked преобразование, чтобы соответствовать ..." который не может быть исправлен [но может быть подавлен только с помощью аннотации @SuppressWarnings ("unchecked")].
вот небольшой пример, чтобы продемонстрировать использование метода "toArray":
public static void main(final String[] args) {
final Map<Integer,String> orderMap = new LinkedHashMap<Integer,String>();
orderMap.put(6, "Six");
orderMap.put(7, "Seven");
orderMap.put(3, "Three");
orderMap.put(100, "Hundered");
orderMap.put(10, "Ten");
final Set<Entry<Integer, String>> mapValues = orderMap.entrySet();
final int maplength = mapValues.size();
final Entry<Integer,String>[] test = new Entry[maplength];
mapValues.toArray(test);
System.out.print("First Key:"+test[0].getKey());
System.out.println(" First Value:"+test[0].getValue());
System.out.print("Last Key:"+test[maplength-1].getKey());
System.out.println(" Last Value:"+test[maplength-1].getValue());
}
// the output geneated is :
First Key:6 First Value:Six
Last Key:10 Last Value:Ten
Я знаю, что пришел слишком поздно, но я хотел бы предложить некоторые альтернативы, не что-то экстраординарное, но некоторые случаи, которые никто не упоминал здесь. В случае, если кто-то не очень заботится об эффективности, но хочет чего-то более простого(возможно, найти последнее значение записи с одной строкой кода), все это будет довольно упрощено с приходом Java 8 . Я предлагаю несколько полезных сценариев.
для полноты, я сравниваю эти альтернативы с решением массивов, которые уже упоминались в этом посте другими пользователями. Я суммирую все случаи, и я думаю, что они будут полезны (когда производительность имеет значение или нет), особенно для новых разработчиков, всегда зависит от вопроса каждой проблемы
Возможны Варианты
использование метода массива
Я взял его из предыдущего ответа, чтобы сделать следующие сравнения. Это решение принадлежит @feresr.
public static String FindLasstEntryWithArrayMethod() {
return String.valueOf(linkedmap.entrySet().toArray()[linkedmap.size() - 1]);
}
использование из класса ArrayList метод
похоже на первое решение с немного другой производительностью
public static String FindLasstEntryWithArrayListMethod() {
List<Entry<Integer, String>> entryList = new ArrayList<Map.Entry<Integer, String>>(linkedmap.entrySet());
return entryList.get(entryList.size() - 1).getValue();
}
Уменьшить Методом
этот метод уменьшит набор элементов до получения последнего элемента потока. Кроме того, он будет возвращать только детерминированные результаты
public static String FindLasstEntryWithReduceMethod() {
return linkedmap.entrySet().stream().reduce((first, second) -> second).orElse(null).getValue();
}
Способ SkipFunction
этот метод получит последний элемент потока, просто пропустив все элементы перед это
public static String FindLasstEntryWithSkipFunctionMethod() {
final long count = linkedmap.entrySet().stream().count();
return linkedmap.entrySet().stream().skip(count - 1).findFirst().get().getValue();
}
Альтернативный Интерфейс Iterable
Iterables.getLast от Google Guava. Он имеет некоторую оптимизацию для Списки и SortedSets тоже
public static String FindLasstEntryWithGuavaIterable() {
return Iterables.getLast(linkedmap.entrySet()).getValue();
}
вот полный исходный код
import com.google.common.collect.Iterables;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class PerformanceTest {
private static long startTime;
private static long endTime;
private static LinkedHashMap<Integer, String> linkedmap;
public static void main(String[] args) {
linkedmap = new LinkedHashMap<Integer, String>();
linkedmap.put(12, "Chaitanya");
linkedmap.put(2, "Rahul");
linkedmap.put(7, "Singh");
linkedmap.put(49, "Ajeet");
linkedmap.put(76, "Anuj");
//call a useless action so that the caching occurs before the jobs starts.
linkedmap.entrySet().forEach(x -> {});
startTime = System.nanoTime();
FindLasstEntryWithArrayListMethod();
endTime = System.nanoTime();
System.out.println("FindLasstEntryWithArrayListMethod : " + "took " + new BigDecimal((endTime - startTime) / 1000000.000).setScale(3, RoundingMode.CEILING) + " milliseconds");
startTime = System.nanoTime();
FindLasstEntryWithArrayMethod();
endTime = System.nanoTime();
System.out.println("FindLasstEntryWithArrayMethod : " + "took " + new BigDecimal((endTime - startTime) / 1000000.000).setScale(3, RoundingMode.CEILING) + " milliseconds");
startTime = System.nanoTime();
FindLasstEntryWithReduceMethod();
endTime = System.nanoTime();
System.out.println("FindLasstEntryWithReduceMethod : " + "took " + new BigDecimal((endTime - startTime) / 1000000.000).setScale(3, RoundingMode.CEILING) + " milliseconds");
startTime = System.nanoTime();
FindLasstEntryWithSkipFunctionMethod();
endTime = System.nanoTime();
System.out.println("FindLasstEntryWithSkipFunctionMethod : " + "took " + new BigDecimal((endTime - startTime) / 1000000.000).setScale(3, RoundingMode.CEILING) + " milliseconds");
startTime = System.currentTimeMillis();
FindLasstEntryWithGuavaIterable();
endTime = System.currentTimeMillis();
System.out.println("FindLasstEntryWithGuavaIterable : " + "took " + (endTime - startTime) + " milliseconds");
}
public static String FindLasstEntryWithReduceMethod() {
return linkedmap.entrySet().stream().reduce((first, second) -> second).orElse(null).getValue();
}
public static String FindLasstEntryWithSkipFunctionMethod() {
final long count = linkedmap.entrySet().stream().count();
return linkedmap.entrySet().stream().skip(count - 1).findFirst().get().getValue();
}
public static String FindLasstEntryWithGuavaIterable() {
return Iterables.getLast(linkedmap.entrySet()).getValue();
}
public static String FindLasstEntryWithArrayListMethod() {
List<Entry<Integer, String>> entryList = new ArrayList<Map.Entry<Integer, String>>(linkedmap.entrySet());
return entryList.get(entryList.size() - 1).getValue();
}
public static String FindLasstEntryWithArrayMethod() {
return String.valueOf(linkedmap.entrySet().toArray()[linkedmap.size() - 1]);
}
}
вот выход с производительностью каждого метода
FindLasstEntryWithArrayListMethod : took 0.162 milliseconds
FindLasstEntryWithArrayMethod : took 0.025 milliseconds
FindLasstEntryWithReduceMethod : took 2.776 milliseconds
FindLasstEntryWithSkipFunctionMethod : took 3.396 milliseconds
FindLasstEntryWithGuavaIterable : took 11 milliseconds
возможно, что-то вроде этого :
LinkedHashMap<Integer, String> myMap;
public String getFirstKey() {
String out = null;
for (int key : myMap.keySet()) {
out = myMap.get(key);
break;
}
return out;
}
public String getLastKey() {
String out = null;
for (int key : myMap.keySet()) {
out = myMap.get(key);
}
return out;
}
это немного грязно, но вы можете переопределить removeEldestEntry
метод LinkedHashMap, который может вам подойти в качестве частного анонимного члена:
private Splat eldest = null;
private LinkedHashMap<Integer, Splat> pastFutures = new LinkedHashMap<Integer, Splat>() {
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Splat> eldest) {
eldest = eldest.getValue();
return false;
}
};
таким образом, вы всегда сможете получить первую запись в своем eldest
- члены. Он будет обновляться каждый раз, когда вы выполняете put
.
это также должно быть легко переопределить put
и set youngest
...
@Override
public Splat put(Integer key, Splat value) {
youngest = value;
return super.put(key, value);
}
все это ломается, когда вы начинаете удалять записи, хотя; не выяснили способ в Клудж, что.
это очень раздражает, что вы не можете иначе получить доступ к голове или хвосту разумным способом ...
Я бы рекомендовал использовать ConcurrentSkipListMap имеющего firstKey()
и lastKey()
методы
хотя linkedHashMap не предоставляет никакого метода для получения первого, последнего или любого конкретного объекта.
но его довольно тривиально, чтобы получить :
- карта orderMap = new LinkedHashMap ();
Установить al = orderMap.набор ключей();
теперь с помощью итератора на объекте al ; вы можете получить любой объект.
Да я сталкивался с той же проблемой, но к счастью, мне нужен только первый элемент... - Вот что я сделал для этого.
private String getDefaultPlayerType()
{
String defaultPlayerType = "";
for(LinkedHashMap.Entry<String,Integer> entry : getLeagueByName(currentLeague).getStatisticsOrder().entrySet())
{
defaultPlayerType = entry.getKey();
break;
}
return defaultPlayerType;
}
Если Вам также нужен последний элемент - я бы посмотрел, как изменить порядок вашей карты-сохраните его в переменной temp, получите доступ к первому элементу в обратной карте (поэтому это будет ваш последний элемент), убейте переменную temp.
вот несколько хороших ответов о том, как изменить порядок hashmap:
как перебрать hashmap в обратном порядке в Java
Если вы используете помощь по приведенной выше ссылке, пожалуйста, дайте им-голоса :) Надеюсь, это может кому-то помочь.
правильно, вы должны вручную перечислить набор ключей до конца linkedlist, затем получить запись по ключу и вернуть эту запись.